Back to index

glibc  2.9
tst-once4.c
Go to the documentation of this file.
00001 /* Copyright (C) 2003, 2004 Free Software Foundation, Inc.
00002    This file is part of the GNU C Library.
00003    Contributed by Ulrich Drepper <drepper@redhat.com>, 2003.
00004 
00005    The GNU C Library is free software; you can redistribute it and/or
00006    modify it under the terms of the GNU Lesser General Public
00007    License as published by the Free Software Foundation; either
00008    version 2.1 of the License, or (at your option) any later version.
00009 
00010    The GNU C Library is distributed in the hope that it will be useful,
00011    but WITHOUT ANY WARRANTY; without even the implied warranty of
00012    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00013    Lesser General Public License for more details.
00014 
00015    You should have received a copy of the GNU Lesser General Public
00016    License along with the GNU C Library; if not, write to the Free
00017    Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
00018    02111-1307 USA.  */
00019 
00020 #include <pthread.h>
00021 #include <stdio.h>
00022 #include <stdlib.h>
00023 #include <time.h>
00024 #include <unistd.h>
00025 
00026 
00027 static pthread_once_t once = PTHREAD_ONCE_INIT;
00028 
00029 static pthread_cond_t cond = PTHREAD_COND_INITIALIZER;
00030 static pthread_mutex_t mut = PTHREAD_MUTEX_INITIALIZER;
00031 
00032 static pthread_barrier_t bar;
00033 
00034 static int global;
00035 static int cl_called;
00036 
00037 static void
00038 once_handler1 (void)
00039 {
00040   if (pthread_mutex_lock (&mut) != 0)
00041     {
00042       puts ("once_handler1: mutex_lock failed");
00043       exit (1);
00044     }
00045 
00046   int r = pthread_barrier_wait (&bar);
00047   if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
00048     {
00049       puts ("once_handler1: barrier_wait failed");
00050       exit (1);
00051     }
00052 
00053   pthread_cond_wait (&cond, &mut);
00054 
00055   /* We should never get here.  */
00056 }
00057 
00058 
00059 static void
00060 once_handler2 (void)
00061 {
00062   global = 1;
00063 }
00064 
00065 
00066 static void
00067 cl (void *arg)
00068 {
00069   ++cl_called;
00070 }
00071 
00072 
00073 static void *
00074 tf1 (void *arg)
00075 {
00076   pthread_cleanup_push (cl, NULL);
00077 
00078   pthread_once (&once, once_handler1);
00079 
00080   pthread_cleanup_pop (0);
00081 
00082   /* We should never get here.  */
00083   puts ("pthread_once in tf returned");
00084   exit (1);
00085 }
00086 
00087 
00088 static void *
00089 tf2 (void *arg)
00090 {
00091   pthread_cleanup_push (cl, NULL);
00092 
00093   int r = pthread_barrier_wait (&bar);
00094   if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
00095     {
00096       puts ("once_handler2: barrier_wait failed");
00097       exit (1);
00098     }
00099 
00100   pthread_cleanup_pop (0);
00101 
00102   pthread_once (&once, once_handler2);
00103 
00104   return NULL;
00105 }
00106 
00107 
00108 static int
00109 do_test (void)
00110 {
00111   pthread_t th[2];
00112 
00113   if (pthread_barrier_init (&bar, NULL, 2) != 0)
00114     {
00115       puts ("barrier_init failed");
00116       return 1;
00117     }
00118 
00119   if (pthread_create (&th[0], NULL, tf1, NULL) != 0)
00120     {
00121       puts ("first create failed");
00122       return 1;
00123     }
00124 
00125   int r = pthread_barrier_wait (&bar);
00126   if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
00127     {
00128       puts ("first barrier_wait failed");
00129       return 1;
00130     }
00131 
00132   if (pthread_mutex_lock (&mut) != 0)
00133     {
00134       puts ("mutex_lock failed");
00135       return 1;
00136     }
00137   /* We unlock the mutex so that we catch the case where the pthread_cond_wait
00138      call incorrectly resumes and tries to get the mutex.  */
00139   if (pthread_mutex_unlock (&mut) != 0)
00140     {
00141       puts ("mutex_unlock failed");
00142       return 1;
00143     }
00144 
00145   if (pthread_create (&th[1], NULL, tf2, NULL) != 0)
00146     {
00147       puts ("second create failed");
00148       return 1;
00149     }
00150 
00151   r = pthread_barrier_wait (&bar);
00152   if (r != 0 && r!= PTHREAD_BARRIER_SERIAL_THREAD)
00153     {
00154       puts ("second barrier_wait failed");
00155       return 1;
00156     }
00157 
00158   /* Give the second thread a chance to reach the pthread_once call.  */
00159   sleep (2);
00160 
00161   /* Cancel the thread.  */
00162   if (pthread_cancel (th[0]) != 0)
00163     {
00164       puts ("cancel failed");
00165       return 1;
00166     }
00167 
00168   void *result;
00169   pthread_join (th[0], &result);
00170   if (result != PTHREAD_CANCELED)
00171     {
00172       puts ("first join didn't return PTHREAD_CANCELED");
00173       return 1;
00174     }
00175 
00176   puts ("joined first thread");
00177 
00178   pthread_join (th[1], &result);
00179   if (result != NULL)
00180     {
00181       puts ("second join didn't return PTHREAD_CANCELED");
00182       return 1;
00183     }
00184 
00185   if (global != 1)
00186     {
00187       puts ("global still 0");
00188       return 1;
00189     }
00190 
00191   if (cl_called != 1)
00192     {
00193       printf ("cl_called = %d\n", cl_called);
00194       return 1;
00195     }
00196 
00197   return 0;
00198 }
00199 
00200 #define TEST_FUNCTION do_test ()
00201 #define TIMEOUT 4
00202 #include "../test-skeleton.c"