/* Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License.
*/
/* time-sem.c has the basics of the semaphores we use in http_main.c. It's intended for timing differences between various methods on an architecture. In practice we've found many things affect which semaphore to be used:
- NFS filesystems absolutely suck for fcntl() and flock()
- uslock absolutely sucks on single-processor IRIX boxes, but absolutely rocks on multi-processor boxes. The converse is true for fcntl. sysvsem seems a moderate balance.
- Under Solaris you can't have too many processes use SEM_UNDO, there might be a tuneable somewhere that increases the limit from 29. We're not sure what the tunable is, so there's a define NO_SEM_UNDO which can be used to simulate us trapping/blocking signals to be able to properly release the semaphore on a clean child death. You'll also need to define NEED_UNION_SEMUN under solaris.
You'll need to define USE_SHMGET_SCOREBOARD if anonymous shared mmap() doesn't work on your system (i.e. linux).
argv[1] is the #children, argv[2] is the #iterations per child
You should run each over many different #children inputs, and choose #iter such that the program runs for at least a second or so... or even longer depending on your patience.
/* * Initialize mutex lock. * Must be safe to call this on a restart.
*/ void
accept_mutex_init(void)
{
lock_it.l_whence = SEEK_SET; /* from current point */
lock_it.l_start = 0; /* -"- */
lock_it.l_len = 0; /* until end of file */
lock_it.l_type = F_WRLCK; /* set exclusive/write lock */
lock_it.l_pid = 0; /* pid not actually interesting */
unlock_it.l_whence = SEEK_SET; /* from current point */
unlock_it.l_start = 0; /* -"- */
unlock_it.l_len = 0; /* until end of file */
unlock_it.l_type = F_UNLCK; /* set exclusive/write lock */
unlock_it.l_pid = 0; /* pid not actually interesting */
printf("opening test-lock-thing in current directory\n");
fcntl_fd = open("test-lock-thing", O_CREAT | O_WRONLY | O_EXCL, 0644); if (fcntl_fd == -1)
{
perror ("open");
fprintf (stderr, "Cannot open lock file: %s\n", "test-lock-thing"); exit (1);
}
unlink("test-lock-thing");
}
void accept_mutex_init(void)
{ #ifdef NEED_UNION_SEMUN /* believe it or not, you need to define this under solaris */ union semun { int val; struct semid_ds *buf;
ushort *array;
}; #endif
/* note: pthread mutexes aren't released on child death, hence the * signal goop ... in a real implementation we'd do special things * during hup, term, usr1.
*/
#ifdef MOVEBREAK /* * Some SysV systems place the shared segment WAY too close * to the dynamic memory break point (sbrk(0)). This severely * limits the use of malloc/sbrk in the program since sbrk will * refuse to move past that point. * * To get around this, we move the break point "way up there", * attach the segment and then move break back down. Ugly
*/ if ((obrk = sbrk(MOVEBREAK)) == (char *) -1) {
perror("sbrk");
} #endif
#define BADSHMAT ((void *)(-1)) if ((result = shmat(shmid, 0, 0)) == BADSHMAT) {
perror("shmat");
} /* * We must avoid leaving segments in the kernel's * (small) tables.
*/ if (shmctl(shmid, IPC_RMID, NULL) != 0) {
perror("shmctl(IPC_RMID)");
} if (result == BADSHMAT) /* now bailout */ exit(1);
#ifdef MOVEBREAK if (obrk == (char *) -1) return; /* nothing else to do */ if (sbrk(-(MOVEBREAK)) == (char *) -1) {
perror("sbrk 2");
} #endif return result;
} #endif
void main (int argc, char **argv)
{ int num_iter; int num_child; int i; struct timeval first; struct timeval last; long ms; int pid; unsignedlong *shared_counter;
if (argc != 3) {
fprintf (stderr, "Usage: time-sem num-child num iter\n"); exit (1);
}
/* allocate shared memory for the shared_counter */
shared_counter = get_shared_mem(sizeof(*shared_counter));
/* initialize counter to 0 */
*shared_counter = 0;
accept_mutex_init ();
/* parent grabs mutex until done spawning children */
accept_mutex_on ();
for (i = 0; i < num_child; ++i) {
pid = fork(); if (pid == 0) { /* child, do our thing */
accept_mutex_child_init(); for (i = 0; i < num_iter; ++i) { unsignedlong tmp;
/* a quick test to see that nothing is screwed up */ if (*shared_counter != 0) {
puts ("WTF! shared_counter != 0 before the children have been started!");
accept_mutex_off (); exit (1);
}
gettimeofday (&first, NULL); /* launch children into action */
accept_mutex_off (); for (i = 0; i < num_child; ++i) { if (wait(NULL) == -1) {
perror ("wait");
}
}
gettimeofday (&last, NULL);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung ist noch experimentell.