• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * once3.c
3  *
4  *
5  * --------------------------------------------------------------------------
6  *
7  *      Pthreads-win32 - POSIX Threads Library for Win32
8  *      Copyright(C) 1998 John E. Bossom
9  *      Copyright(C) 1999,2005 Pthreads-win32 contributors
10  *
11  *      Contact Email: rpj@callisto.canberra.edu.au
12  *
13  *      The current list of contributors is contained
14  *      in the file CONTRIBUTORS included with the source
15  *      code distribution. The list can also be seen at the
16  *      following World Wide Web location:
17  *      http://sources.redhat.com/pthreads-win32/contributors.html
18  *
19  *      This library is free software; you can redistribute it and/or
20  *      modify it under the terms of the GNU Lesser General Public
21  *      License as published by the Free Software Foundation; either
22  *      version 2 of the License, or (at your option) any later version.
23  *
24  *      This library is distributed in the hope that it will be useful,
25  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
26  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
27  *      Lesser General Public License for more details.
28  *
29  *      You should have received a copy of the GNU Lesser General Public
30  *      License along with this library in the file COPYING.LIB;
31  *      if not, write to the Free Software Foundation, Inc.,
32  *      59 Temple Place - Suite 330, Boston, MA 02111-1307, USA
33  *
34  * --------------------------------------------------------------------------
35  *
36  * Create several pthread_once objects and channel several threads
37  * through each. Make the init_routine cancelable and cancel them with
38  * waiters waiting.
39  *
40  * Depends on API functions:
41  *	pthread_once()
42  *	pthread_create()
43  *      pthread_testcancel()
44  *      pthread_cancel()
45  *      pthread_once()
46  */
47 
48 /* #define ASSERT_TRACE */
49 
50 #include "test.h"
51 
52 #define NUM_THREADS 100 /* Targeting each once control */
53 #define NUM_ONCE    10
54 
55 pthread_once_t o = PTHREAD_ONCE_INIT;
56 pthread_once_t once[NUM_ONCE];
57 
58 typedef struct {
59   int i;
60   CRITICAL_SECTION cs;
61 } sharedInt_t;
62 
63 static sharedInt_t numOnce = {0, {0}};
64 static sharedInt_t numThreads = {0, {0}};
65 
66 void
myfunc(void)67 myfunc(void)
68 {
69   EnterCriticalSection(&numOnce.cs);
70   numOnce.i++;
71   assert(numOnce.i > 0);
72   LeaveCriticalSection(&numOnce.cs);
73   /* Simulate slow once routine so that following threads pile up behind it */
74   Sleep(10);
75   /* test for cancelation late so we're sure to have waiters. */
76   pthread_testcancel();
77 }
78 
79 void *
mythread(void * arg)80 mythread(void * arg)
81 {
82   /*
83    * Cancel every thread. These threads are deferred cancelable only, so
84    * only the thread performing the once routine (my_func) will see it (there are
85    * no other cancelation points here). The result will be that every thread
86    * eventually cancels only when it becomes the new once thread.
87    */
88   assert(pthread_cancel(pthread_self()) == 0);
89   assert(pthread_once(&once[(int) (size_t) arg], myfunc) == 0);
90   EnterCriticalSection(&numThreads.cs);
91   numThreads.i++;
92   LeaveCriticalSection(&numThreads.cs);
93   return 0;
94 }
95 
96 int
main()97 main()
98 {
99   pthread_t t[NUM_THREADS][NUM_ONCE];
100   int i, j;
101 
102   //printf ("Is ok\n");
103   //return 1;
104   InitializeCriticalSection(&numThreads.cs);
105   InitializeCriticalSection(&numOnce.cs);
106 
107   for (j = 0; j < NUM_ONCE; j++)
108     {
109       once[j] = o;
110 
111       for (i = 0; i < NUM_THREADS; i++)
112         {
113 	  int r1 =
114             pthread_create(&t[i][j], NULL, mythread, (void *) (size_t) j);
115 	  if (r1 == EAGAIN) { --i; Sleep(0); continue; }
116 	  if (r1 != 0)
117 	  fprintf (stderr, "create returns %d (EAGAIN:%d)\n",r1, EAGAIN);
118 	  assert (r1 == 0);
119         }
120     }
121 
122   for (j = 0; j < NUM_ONCE; j++)
123     for (i = 0; i < NUM_THREADS; i++)
124       if (pthread_join(t[i][j], NULL) != 0)
125         printf("Join failed for [thread,once] = [%d,%d]\n", i, j);
126 
127   /*
128    * All threads will cancel, none will return normally from
129    * pthread_once and so numThreads should never be incremented. However,
130    * numOnce should be incremented by every thread (NUM_THREADS*NUM_ONCE).
131    */
132   assert(numOnce.i == NUM_ONCE * NUM_THREADS);
133   assert(numThreads.i == 0);
134 
135   DeleteCriticalSection(&numOnce.cs);
136   DeleteCriticalSection(&numThreads.cs);
137 
138   return 0;
139 }
140