• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * once4.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
38  * waiters waiting. Vary the priorities.
39  *
40  * Depends on API functions:
41  *	pthread_once()
42  *	pthread_create()
43  *      pthread_testcancel()
44  *      pthread_cancel()
45  *      pthread_once()
46  */
47 
48 #include "test.h"
49 
50 #define NUM_THREADS 100 /* Targeting each once control */
51 #define NUM_ONCE    10
52 
53 pthread_once_t o = PTHREAD_ONCE_INIT;
54 pthread_once_t once[NUM_ONCE];
55 
56 typedef struct {
57   int i;
58   CRITICAL_SECTION cs;
59 } sharedInt_t;
60 
61 static sharedInt_t numOnce = {0, {0}};
62 static sharedInt_t numThreads = {0, {0}};
63 
64 typedef struct {
65   int threadnum;
66   int oncenum;
67   int myPrio;
68   HANDLE w32Thread;
69 } bag_t;
70 
71 static bag_t threadbag[NUM_THREADS][NUM_ONCE];
72 
73 CRITICAL_SECTION print_lock;
74 
75 void
mycleanupfunc(void * arg)76 mycleanupfunc(void * arg)
77 {
78   bag_t * bag = (bag_t *) arg;
79   EnterCriticalSection(&print_lock);
80   /*      once thrd  prio error */
81   printf("%4d %4d %4d %4d\n",
82 	 bag->oncenum,
83 	 bag->threadnum,
84 	 bag->myPrio,
85 	 bag->myPrio - GetThreadPriority(bag->w32Thread));
86   LeaveCriticalSection(&print_lock);
87 }
88 
89 void
myinitfunc(void)90 myinitfunc(void)
91 {
92   EnterCriticalSection(&numOnce.cs);
93   numOnce.i++;
94   LeaveCriticalSection(&numOnce.cs);
95   /* Simulate slow once routine so that following threads pile up behind it */
96   Sleep(10);
97   /* test for cancelation late so we're sure to have waiters. */
98   pthread_testcancel();
99 }
100 
101 void *
mythread(void * arg)102 mythread(void * arg)
103 {
104   bag_t * bag = (bag_t *) arg;
105   struct sched_param param;
106 
107   /*
108    * Cancel every thread. These threads are deferred cancelable only, so
109    * only the thread performing the init_routine will see it (there are
110    * no other cancelation points here). The result will be that every thread
111    * eventually cancels only when it becomes the new initter.
112    */
113   pthread_t self = pthread_self();
114   bag->w32Thread = pthread_getw32threadhandle_np(self);
115   /*
116    * Set priority between -2 and 2 inclusive.
117    */
118   bag->myPrio = (bag->threadnum % 5) - 2;
119   param.sched_priority = bag->myPrio;
120   pthread_setschedparam(self, SCHED_OTHER, &param);
121 
122   /* Trigger a cancellation at the next cancellation point in this thread */
123   pthread_cancel(self);
124 #if 0
125   pthread_cleanup_push(mycleanupfunc, arg);
126   assert(pthread_once(&once[bag->oncenum], myinitfunc) == 0);
127   pthread_cleanup_pop(1);
128 #else
129   assert(pthread_once(&once[bag->oncenum], myinitfunc) == 0);
130 #endif
131   EnterCriticalSection(&numThreads.cs);
132   numThreads.i++;
133   LeaveCriticalSection(&numThreads.cs);
134   return 0;
135 }
136 
137 int
main()138 main()
139 {
140   pthread_t t[NUM_THREADS][NUM_ONCE];
141   int i, j, cpus;
142 
143   //fprintf(stderr, "Skipped (hangs)\n");
144   //return 1;
145   InitializeCriticalSection(&print_lock);
146   InitializeCriticalSection(&numThreads.cs);
147   InitializeCriticalSection(&numOnce.cs);
148 
149 #if 0
150   /*       once thrd  prio change */
151   printf("once thrd  prio  error\n");
152 #endif
153 
154   /*
155    * Set the priority class to realtime - otherwise normal
156    * Windows random priority boosting will obscure any problems.
157    */
158   cpus = pthread_num_processors_np();
159   fprintf(stderr,"CPU count: %d\n", cpus);
160   if (cpus <= 1) {
161     fprintf(stderr, "This test uses realtime scheduling and requires a multi-core to prevent system hang.\n");
162     exit(0);
163   }
164 
165   pthread_set_num_processors_np(cpus-1);
166   //SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
167   SetPriorityClass(GetCurrentProcess(), BELOW_NORMAL_PRIORITY_CLASS);
168   /* Set main thread to lower prio than threads */
169   SetThreadPriority(GetCurrentThread(), -2);
170   printf("CPU count (reduced): %d\n", pthread_num_processors_np());
171 
172   for (j = 0; j < NUM_ONCE; j++)
173     {
174       once[j] = o;
175 
176       for (i = 0; i < NUM_THREADS; i++)
177         {
178 	  int r1;
179 	  bag_t * bag = &threadbag[i][j];
180 	  bag->threadnum = i;
181 	  bag->oncenum = j;
182           r1 = pthread_create(&t[i][j], NULL, mythread, (void *) bag);
183 	  if (r1 == EAGAIN) { --i; Sleep(0); continue; }
184 	  assert (r1 == 0);
185         }
186     }
187 
188   for (j = 0; j < NUM_ONCE; j++)
189     for (i = 0; i < NUM_THREADS; i++)
190       if (pthread_join(t[i][j], NULL) != 0)
191         printf("Join failed for [thread,once] = [%d,%d]\n", i, j);
192 
193   /*
194    * All threads will cancel, none will return normally from
195    * pthread_once and so numThreads should never be incremented. However,
196    * numOnce should be incremented by every thread (NUM_THREADS*NUM_ONCE).
197    */
198   assert(numOnce.i == NUM_ONCE * NUM_THREADS);
199   assert(numThreads.i == 0);
200 
201   DeleteCriticalSection(&numOnce.cs);
202   DeleteCriticalSection(&numThreads.cs);
203   DeleteCriticalSection(&print_lock);
204 
205   return 0;
206 }
207