Bug 19821 - Timer crash when repeat create-start-delete several times
Summary: Timer crash when repeat create-start-delete several times
Status: RESOLVED DUPLICATE of bug 20116
Alias: None
Product: glibc
Classification: Unclassified
Component: time (show other bugs)
Version: 2.21
: P2 normal
Target Milestone: ---
Assignee: Not yet assigned to anyone
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-03-14 16:11 UTC by Anton Hrytsevich
Modified: 2019-12-09 19:45 UTC (History)
3 users (show)

See Also:
Host:
Target:
Build:
Last reconfirmed:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Anton Hrytsevich 2016-03-14 16:11:23 UTC
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;
}
Comment 1 Andreas Schwab 2016-03-14 16:25:26 UTC
timer.c:13:17: error: variably modified ‘mutex’ at file scope
 pthread_mutex_t mutex[TIMER_COUNT] = {PTHREAD_MUTEX_INITIALIZER};
                 ^
Comment 2 Anton Hrytsevich 2016-03-14 16:29:11 UTC
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;
}
Comment 3 Andreas Schwab 2016-03-14 16:33:39 UTC
timer.c:11:20: error: unknown type name ‘sigval’
 void timer_thread (sigval signal_value) {
                    ^
Comment 4 Anton Hrytsevich 2016-03-14 16:34:56 UTC
Use build command-line: /usr/bin/c++    -lrt -lpthread -g ./main.cc
Comment 5 Andreas Schwab 2016-03-14 16:38:00 UTC
Please provide a C test case.
Comment 6 Anton Hrytsevich 2016-03-14 16:49:25 UTC
I don't understood you. What you mean under "C test case"?
Comment 7 Andreas Schwab 2016-03-14 17:04:24 UTC
A test case in plain C.
Comment 8 Anton Hrytsevich 2016-03-14 17:05:25 UTC
I haven't so.
Comment 9 Florian Weimer 2016-03-14 19:10:48 UTC
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;
}
Comment 10 Adhemerval Zanella 2019-12-09 19:45:16 UTC
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 ***