If run this code on Ubuntu 15.04 and glibc 2.21 it will crash with SIGSEGV. #include <pthread.h> #include <sys/signal.h> #include <stdio.h> #include <assert.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <sys/resource.h> const int TIMER_COUNT = 300; pthread_mutex_t mutex[TIMER_COUNT] = {PTHREAD_MUTEX_INITIALIZER}; pthread_cond_t cond[TIMER_COUNT] = {PTHREAD_COND_INITIALIZER}; void timer_thread(sigval signal_value) { int status; // printf ("Prepare wait unlock mutex %d\n", signal_value.sival_int); status = pthread_mutex_lock(&mutex[signal_value.sival_int]); assert(!status && "Lock mutex"); status = pthread_cond_signal(&cond[signal_value.sival_int]); assert(!status && "Signal condition"); //printf ("Timer %d, thread id %ld\n", signal_value.sival_int, pthread_self()); status = pthread_mutex_unlock(&mutex[signal_value.sival_int]); assert(!status && "Unlock mutex"); } int main(int argc, char* argv[]) { for (int i = 0; i < 10000; i++) { printf("\n~~~~~~~ Iteration #%06d ~~~~~~~~~~~~~\n", i + 1); int status = 0; timer_t timer_id[TIMER_COUNT] = {}; memset(&timer_id[0], 0, sizeof(timer_t) * TIMER_COUNT); printf("Start creating timers! \n"); for (int j = 0; j < TIMER_COUNT; j++) { //printf(" ___Subiteration #%02d___\n", j + 1); itimerspec ts = {}; sigevent se = {}; memset(&ts, 0, sizeof(itimerspec)); memset(&se, 0, sizeof(sigevent)); se.sigev_notify = SIGEV_THREAD; se.sigev_value.sival_int = j; se.sigev_notify_function = timer_thread; // Specify a repeating timer that fires each 100000 nanosec. ts.it_value.tv_sec = 0; ts.it_value.tv_nsec = 1000000; ts.it_interval.tv_sec = 0; ts.it_interval.tv_nsec = 1000000; // printf ("Creating timer \n"); status = timer_create(CLOCK_REALTIME, &se, &timer_id[j]); assert(!status && "Create timer"); //printf ("Setting timer %#08x...\n", *(int*)&timer_id[j]); status = timer_settime(timer_id[j], 0, &ts, 0); assert(!status && "Set timer"); } printf("All timers has already started! \n"); for (int j = 0; j < TIMER_COUNT; j++) { status = pthread_mutex_lock(&mutex[j]); assert(!status && "Lock mutex"); status = pthread_cond_wait(&cond[j], &mutex[j]); assert(!status && "Wait on condition"); status = pthread_mutex_unlock(&mutex[j]); assert(!status && "Unlock mutex"); } printf("All timers done! \n"); printf("Start timers deleted! \n"); for (int j = 0; j < TIMER_COUNT; j++) { // stop and delete //printf("Delete timer %#08x...\n", *(int*)&timer_id[j]); status = pthread_mutex_lock(&mutex[j]); assert(!status && "Lock mutex"); status = timer_delete(timer_id[j]); assert(!status && "Fail delete timer"); status = pthread_mutex_unlock(&mutex[j]); assert(!status && "Unlock mutex"); } printf("All timers deleted! \n"); } printf("Success!\n"); return 0; }
timer.c:13:17: error: variably modified ‘mutex’ at file scope pthread_mutex_t mutex[TIMER_COUNT] = {PTHREAD_MUTEX_INITIALIZER}; ^
Nevermind, take version without mutex it's faol too. #include <pthread.h> #include <sys/signal.h> #include <stdio.h> #include <assert.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <sys/resource.h> void timer_thread (sigval signal_value) { printf ("Timer callback!\n"); } int main(int argc, char* argv[]) { const int TIMER_COUNT = 300; for (int i = 0; i < 10000; i++) { printf("\n~~~~~~~ Iteration #%06d ~~~~~~~~~~~~~\n", i+1); int status = 0; timer_t timer_id[TIMER_COUNT] = {}; memset(&timer_id[0], 0, sizeof(timer_t)*TIMER_COUNT); printf ("Start creating timers! \n"); for (int j = 0; j < TIMER_COUNT; j++) { printf(" ___Subiteration #%02d___\n", j+1); struct itimerspec ts = {}; struct sigevent se = {}; memset(&ts, 0, sizeof(itimerspec)); memset(&se, 0, sizeof(sigevent)); se.sigev_notify = SIGEV_THREAD; se.sigev_value.sival_int = j; se.sigev_notify_function = timer_thread; // Specify a repeating timer that fires each 100000 nanosec. memset(&ts, 0, sizeof(ts)); ts.it_value.tv_nsec = 100000; ts.it_interval.tv_nsec = 100000; //printf ("Creating timer\n"); status = timer_create(CLOCK_REALTIME, &se, &timer_id[j]); assert(!status && "Create timer"); //printf ("Setting timer %#08x...\n", *(unsigned int*)&timer_id[j]); status = timer_settime(timer_id[j], 0, &ts, 0); assert(!status && "Set timer"); } printf ("All timers has already started! \n"); printf ("Start timers deleted! \n"); for (int j = 0; j < TIMER_COUNT; j++) { usleep(100); //stop and delete printf ("Delete timer %#08x...\n", *(int*)&timer_id[j]); status = timer_delete(timer_id[j]); assert(!status && "Fail delete timer"); } printf ("All timers deleted! \n"); } printf("Success!\n"); return 0; }
timer.c:11:20: error: unknown type name ‘sigval’ void timer_thread (sigval signal_value) { ^
Use build command-line: /usr/bin/c++ -lrt -lpthread -g ./main.cc
Please provide a C test case.
I don't understood you. What you mean under "C test case"?
A test case in plain C.
I haven't so.
The C version goes like this. #include <pthread.h> #include <sys/signal.h> #include <stdio.h> #include <assert.h> #include <unistd.h> #include <string.h> #include <errno.h> #include <sys/resource.h> void timer_thread (union sigval signal_value) { printf ("Timer callback!\n"); } int main(int argc, char* argv[]) { #define TIMER_COUNT 300 for (int i = 0; i < 10000; i++) { printf("\n~~~~~~~ Iteration #%06d ~~~~~~~~~~~~~\n", i+1); int status = 0; timer_t timer_id[TIMER_COUNT] = {}; memset(&timer_id[0], 0, sizeof(timer_t)*TIMER_COUNT); printf ("Start creating timers! \n"); for (int j = 0; j < TIMER_COUNT; j++) { printf(" ___Subiteration #%02d___\n", j+1); struct itimerspec ts = {}; struct sigevent se = {}; memset(&ts, 0, sizeof(struct itimerspec)); memset(&se, 0, sizeof(struct sigevent)); se.sigev_notify = SIGEV_THREAD; se.sigev_value.sival_int = j; se.sigev_notify_function = timer_thread; // Specify a repeating timer that fires each 100000 nanosec. memset(&ts, 0, sizeof(ts)); ts.it_value.tv_nsec = 100000; ts.it_interval.tv_nsec = 100000; //printf ("Creating timer\n"); status = timer_create(CLOCK_REALTIME, &se, &timer_id[j]); assert(!status && "Create timer"); //printf ("Setting timer %#08x...\n", *(unsigned int*)&timer_id[j]); status = timer_settime(timer_id[j], 0, &ts, 0); assert(!status && "Set timer"); } printf ("All timers has already started! \n"); printf ("Start timers deleted! \n"); for (int j = 0; j < TIMER_COUNT; j++) { usleep(100); //stop and delete printf ("Delete timer %#08x...\n", *(int*)&timer_id[j]); status = timer_delete(timer_id[j]); assert(!status && "Fail delete timer"); } printf ("All timers deleted! \n"); } printf("Success!\n"); return 0; }
The testcase on comment #1 does fail on glibc 2.21 with: Program terminated with signal SIGSEGV, Segmentation fault. #0 __pthread_create_2_1 (newthread=newthread@entry=0x7f34d470ae28, attr=attr@entry=0x7f34d57c6da8, start_ro utine=start_routine@entry=0x7f34d48d8e20 <timer_sigev_thread>, arg=<optimized out>) at pthread_create.c:698 698 if (pd->stopped_start) [Current thread is 1 (LWP 24386)] (gdb) p pd $1 = (struct pthread *) 0x7f34ceffd700 (gdb) p *pd Cannot access memory at address 0x7f34ceffd700 (gdb) bt #0 __pthread_create_2_1 (newthread=newthread@entry=0x7f34d470ae28, attr=attr@entry=0x7f34d57c6da8, start_ro utine=start_routine@entry=0x7f34d48d8e20 <timer_sigev_thread>, arg=<optimized out>) at pthread_create.c:698 #1 0x00007f34d48d8e0c in timer_helper_thread (arg=<optimized out>) at ../sysdeps/unix/sysv/linux/timer_routines.c:125 #2 0x00007f34d4717da4 in start_thread (arg=<optimized out>) at pthread_create.c:333 #3 0x00007f34d481867d in clone () at ../sysdeps/unix/sysv/linux/x86_64/clone.S:109 This is similar to BZ#20116 and cherry-pick f8bf15febcaf137bbec5a61101e88cd5a9d56ca8 on 2.21 does not trigger the issue anymore (where I constantly see the segfault on lest than 1000 iterations prior the fix). I couldn't also reproduce on master. *** This bug has been marked as a duplicate of bug 20116 ***