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, ¶m);
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