Home | History | Annotate | Download | only in tests
      1 /* Use a semaphore to implement mutual exclusion. */
      2 
      3 #include <assert.h>
      4 #include <fcntl.h>     /* O_CREAT */
      5 #include <pthread.h>
      6 #include <semaphore.h>
      7 #include <stdio.h>     /* printf() */
      8 #include <stdlib.h>    /* exit()  */
      9 #include <unistd.h>    /* sleep() */
     10 
     11 /* Local functions declarations. */
     12 
     13 static void* thread_func(void*);
     14 
     15 
     16 /* Local variables. */
     17 
     18 /* s_sem protects s_d3. */
     19 static sem_t* s_sem;
     20 
     21 static double s_d1; /* accessed before thread creation and in the created */
     22                     /* thread (not a race). */
     23 static double s_d2; /* accessed in the created thread and after the join */
     24                     /* (not a race). */
     25 static double s_d3; /* accessed simultaneously from both threads (race). */
     26 static int    s_debug     = 0;
     27 static int    s_do_printf = 0;
     28 static int    s_do_mutual_exclusion = 0;
     29 
     30 
     31 /* Function definitions. */
     32 
     33 int main(int argc, char** argv)
     34 {
     35   int optchar;
     36   pthread_t threadid;
     37   char semaphore_name[32];
     38 
     39   while ((optchar = getopt(argc, argv, "dmp")) != EOF)
     40   {
     41     switch (optchar)
     42     {
     43     case 'd':
     44       s_debug = 1;
     45       break;
     46     case 'm':
     47       s_do_mutual_exclusion = 1;
     48       break;
     49     case 'p':
     50       s_do_printf = 1;
     51       break;
     52     default:
     53       assert(0);
     54     }
     55   }
     56 
     57   /*
     58    * Use the ipcs and ipcrm commands to clean up named semaphores left by
     59    * aborted instances of this process.
     60    */
     61   snprintf(semaphore_name, sizeof(semaphore_name), "/drd-sem-open-test-%ld",
     62 	   (long) getpid());
     63   s_sem = sem_open(semaphore_name, O_CREAT | O_EXCL, 0600, 1);
     64   if (s_sem == SEM_FAILED)
     65   {
     66     fprintf(stderr, "Failed to create a semaphore with name %s\n",
     67             semaphore_name);
     68     exit(1);
     69   }
     70 
     71   /*
     72    * Switch to line-buffered mode, such that timing information can be
     73    * obtained for each printf() call with strace.
     74    */
     75   setlinebuf(stdout);
     76 
     77   if (s_debug)
     78   {
     79     printf("&s_d1 = %p; &s_d2 = %p; &s_d3 = %p\n", &s_d1, &s_d2, &s_d3);
     80   }
     81 
     82   s_d1 = 1;
     83   s_d3 = 3;
     84 
     85   pthread_create(&threadid, 0, thread_func, 0);
     86 
     87   sleep(1); /* Wait until thread_func() finished. */
     88 
     89   {
     90     if (s_do_mutual_exclusion) sem_wait(s_sem);
     91     s_d3++;
     92     if (s_do_mutual_exclusion) sem_post(s_sem);
     93   }
     94 
     95   /* Wait until the thread finished. */
     96   pthread_join(threadid, 0);
     97   if (s_do_printf) printf("s_d2 = %g (should be 2)\n", s_d2);
     98   if (s_do_printf) printf("s_d3 = %g (should be 5)\n", s_d3);
     99 
    100   sem_close(s_sem);
    101   sem_unlink(semaphore_name);
    102 
    103   return 0;
    104 }
    105 
    106 static void* thread_func(void* thread_arg)
    107 {
    108   if (s_do_printf)
    109   {
    110     printf("s_d1 = %g (should be 1)\n", s_d1);
    111   }
    112   s_d2 = 2;
    113   {
    114     if (s_do_mutual_exclusion) sem_wait(s_sem);
    115     s_d3++;
    116     if (s_do_mutual_exclusion) sem_post(s_sem);
    117   }
    118   return 0;
    119 }
    120