1 /* Copyright (C) 2001-2006 Artifex Software, Inc.
2 All Rights Reserved.
3
4 This software is provided AS-IS with no warranty, either express or
5 implied.
6
7 This software is distributed under license and may not be copied, modified
8 or distributed except as expressly authorized under the terms of that
9 license. Refer to licensing information at http://www.artifex.com/
10 or contact Artifex Software, Inc., 7 Mt. Lassen Drive - Suite A-134,
11 San Rafael, CA 94903, U.S.A., +1(415)492-9861, for further information.
12 */
13
14 /* $Id: gp_wsync.c 9130 2008-10-08 05:56:27Z ray $ */
15 /* MS Windows (Win32) thread / semaphore / monitor implementation */
16 /* original multi-threading code by John Desrosiers */
17 #include "malloc_.h"
18 #include "gserror.h"
19 #include "gserrors.h"
20 #include "gpsync.h"
21 #include "windows_.h"
22 #include <process.h>
23
24 /* ------- Synchronization primitives -------- */
25
26 /* Semaphore supports wait/signal semantics */
27
28 typedef struct win32_semaphore_s {
29 HANDLE handle; /* returned from CreateSemaphore */
30 } win32_semaphore;
31
32 uint
gp_semaphore_sizeof(void)33 gp_semaphore_sizeof(void)
34 {
35 return sizeof(win32_semaphore);
36 }
37
38 int /* if sema <> 0 rets -ve error, 0 ok; if sema == 0, 0 movable, 1 fixed */
gp_semaphore_open(gp_semaphore * sema)39 gp_semaphore_open(
40 gp_semaphore * sema /* create semaphore here */
41 )
42 {
43 win32_semaphore *const winSema = (win32_semaphore *)sema;
44
45 if (winSema) {
46 winSema->handle = CreateSemaphore(NULL, 0, max_int, NULL);
47 return
48 (winSema->handle != NULL ? 0 :
49 gs_note_error(gs_error_unknownerror));
50 } else
51 return 0; /* Win32 semaphores handles may be moved */
52 }
53
54 int
gp_semaphore_close(gp_semaphore * sema)55 gp_semaphore_close(
56 gp_semaphore * sema /* semaphore to affect */
57 )
58 {
59 win32_semaphore *const winSema = (win32_semaphore *)sema;
60
61 if (winSema->handle != NULL)
62 CloseHandle(winSema->handle);
63 winSema->handle = NULL;
64 return 0;
65 }
66
67 int /* rets 0 ok, -ve error */
gp_semaphore_wait(gp_semaphore * sema)68 gp_semaphore_wait(
69 gp_semaphore * sema /* semaphore to affect */
70 )
71 {
72 win32_semaphore *const winSema = (win32_semaphore *)sema;
73
74 return
75 (WaitForSingleObject(winSema->handle, INFINITE) == WAIT_OBJECT_0
76 ? 0 : gs_error_unknownerror);
77 }
78
79 int /* rets 0 ok, -ve error */
gp_semaphore_signal(gp_semaphore * sema)80 gp_semaphore_signal(
81 gp_semaphore * sema /* semaphore to affect */
82 )
83 {
84 win32_semaphore *const winSema = (win32_semaphore *)sema;
85
86 return
87 (ReleaseSemaphore(winSema->handle, 1, NULL) ? 0 :
88 gs_error_unknownerror);
89 }
90
91
92 /* Monitor supports enter/leave semantics */
93
94 typedef struct win32_monitor_s {
95 CRITICAL_SECTION lock; /* critical section lock */
96 } win32_monitor;
97
98 uint
gp_monitor_sizeof(void)99 gp_monitor_sizeof(void)
100 {
101 return sizeof(win32_monitor);
102 }
103
104 int /* if sema <> 0 rets -ve error, 0 ok; if sema == 0, 0 movable, 1 fixed */
gp_monitor_open(gp_monitor * mon)105 gp_monitor_open(
106 gp_monitor * mon /* create monitor here */
107 )
108 {
109 win32_monitor *const winMon = (win32_monitor *)mon;
110
111 if (mon) {
112 InitializeCriticalSection(&winMon->lock); /* returns no status */
113 return 0;
114 } else
115 return 1; /* Win32 critical sections mutsn't be moved */
116 }
117
118 int
gp_monitor_close(gp_monitor * mon)119 gp_monitor_close(
120 gp_monitor * mon /* monitor to affect */
121 )
122 {
123 win32_monitor *const winMon = (win32_monitor *)mon;
124
125 DeleteCriticalSection(&winMon->lock); /* rets no status */
126 return 0;
127 }
128
129 int /* rets 0 ok, -ve error */
gp_monitor_enter(gp_monitor * mon)130 gp_monitor_enter(
131 gp_monitor * mon /* monitor to affect */
132 )
133 {
134 win32_monitor *const winMon = (win32_monitor *)mon;
135
136 EnterCriticalSection(&winMon->lock); /* rets no status */
137 return 0;
138 }
139
140 int /* rets 0 ok, -ve error */
gp_monitor_leave(gp_monitor * mon)141 gp_monitor_leave(
142 gp_monitor * mon /* monitor to affect */
143 )
144 {
145 win32_monitor *const winMon = (win32_monitor *)mon;
146
147 LeaveCriticalSection(&winMon->lock); /* rets no status */
148 return 0;
149 }
150
151 /* --------- Thread primitives ---------- */
152
153 typedef struct gp_thread_creation_closure_s {
154 gp_thread_creation_callback_t function; /* function to start */
155 void *data; /* magic data to pass to thread */
156 } gp_thread_creation_closure;
157
158 /* Origin of new threads started by gp_create_thread */
159 static void
gp_thread_begin_wrapper(void * thread_data)160 gp_thread_begin_wrapper(
161 void *thread_data /* gp_thread_creation_closure passed as magic data */
162 )
163 {
164 gp_thread_creation_closure closure;
165
166 closure = *(gp_thread_creation_closure *)thread_data;
167 free(thread_data);
168 (*closure.function)(closure.data);
169 _endthread();
170 }
171
172 /* Call a function on a brand new thread */
173 int /* 0 ok, -ve error */
gp_create_thread(gp_thread_creation_callback_t function,void * data)174 gp_create_thread(
175 gp_thread_creation_callback_t function, /* function to start */
176 void *data /* magic data to pass to thread fn */
177 )
178 {
179 /* Create the magic closure that thread_wrapper gets passed */
180 gp_thread_creation_closure *closure =
181 (gp_thread_creation_closure *)malloc(sizeof(*closure));
182
183 if (!closure)
184 return gs_error_VMerror;
185 closure->function = function;
186 closure->data = data;
187
188 /*
189 * Start thread_wrapper. The Watcom _beginthread returns (int)(-1) if
190 * the call fails. The Microsoft _beginthread returns -1 (according to
191 * the doc, even though the return type is "unsigned long" !!!) if the
192 * call fails; we aren't sure what the Borland _beginthread returns.
193 * The hack with ~ avoids a source code commitment as to whether the
194 * return type is [u]int or [u]long.
195 *
196 * BEGIN_THREAD is a macro (defined in windows_.h) because _beginthread
197 * takes different arguments in Watcom C.
198 */
199 if (~BEGIN_THREAD(gp_thread_begin_wrapper, 128*1024, closure) != 0)
200 return 0;
201 return_error(gs_error_unknownerror);
202 }
203
204