/*********************************************************************** * This is a STC to show that fcntl hangs. * * It tries to use fcntl() for file locking. It creates a temporary * file, the uses fork to spawn a number of children. Each child opens * the file, then repeatedly uses flock to lock and unlock it. * * While each child has the lock, it increments a counter stored in * shared memory in a racy way, passing the current value to a function * which sleeps briefly, then returns the incremented counter. * * If all works correctly, the counter should end up be incremented * by each child iteration. * * However, this test currently just hangs. * * Compile: gcc -Wall -o stc-flock-fork stc-flock-fork.c ***********************************************************************/ #include #include #include #include #include #include #include #define NUM_TEST_ITERS 1 #define MAX_ITER 10 #define CHILDREN 3 #define MAX_COUNT (MAX_ITER * CHILDREN) /* Counter stored in shared memory. */ static volatile int *x; /* A temporary file used for fcntl. */ char tmpfilename[] = "/tmp/fcntlXXXXXX"; struct flock mutex_lock_it; struct flock mutex_unlock_it; /* a slower more racy way to implement (*x)++ */ static int increment(int n) { usleep(1); return n+1; } /* Fork and use fcntl to lock and unlock the file repeatedly in the child. */ void make_child(int childnum, int verbose, int trylock, pid_t *pid) { if ((*pid = fork()) < 0) { perror("fork failed"); exit(1); } else if (*pid == 0) { int fd2 = open(tmpfilename, O_RDWR); if (fd2 < 0) { perror("child open"); exit(1); } int rc; int i; for (i=0; i 1) ? 1 : 0; /* Create the temporary file. */ fd = mkstemp(tmpfilename); if (fd < 0) { perror("open failed"); exit(1); } close(fd); /* Initialize shared memory */ init_shm(); /* Setup mutexes */ mutex_lock_it.l_whence = SEEK_SET; /* from current point */ mutex_lock_it.l_start = 0; /* -"- */ mutex_lock_it.l_len = 0; /* until end of file */ mutex_lock_it.l_type = F_WRLCK; /* set exclusive/write lock */ mutex_lock_it.l_pid = 0; /* pid not actually interesting */ mutex_unlock_it.l_whence = SEEK_SET; /* from current point */ mutex_unlock_it.l_start = 0; /* -"- */ mutex_unlock_it.l_len = 0; /* until end of file */ mutex_unlock_it.l_type = F_UNLCK; /* set exclusive/write lock */ mutex_unlock_it.l_pid = 0; /* pid not actually interesting */ /* Perform the test multiple times. */ for (i = 0; i < NUM_TEST_ITERS; ++i) { /* Create the children. */ for (n = 0; n < CHILDREN; n++) make_child(n, verbose, 0, &child[n]); /* Wait for them to finish. */ for (n = 0; n < CHILDREN; n++) await_child(child[n]); /* Check counter */ if (*x != MAX_COUNT) { printf("Iteration %d: FAILED: *x (%d) != MAX_COUNT (%d)\n", i, *x, MAX_COUNT); exit(1); } } /* Clean up. */ unlink(tmpfilename); return 0; }