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