17dd7cddfSDavid du Colombier /* Copyright (C) 1999 Aladdin Enterprises. All rights reserved.
27dd7cddfSDavid du Colombier
3*593dc095SDavid du Colombier This software is provided AS-IS with no warranty, either express or
4*593dc095SDavid du Colombier implied.
57dd7cddfSDavid du Colombier
6*593dc095SDavid du Colombier This software is distributed under license and may not be copied,
7*593dc095SDavid du Colombier modified or distributed except as expressly authorized under the terms
8*593dc095SDavid du Colombier of the license contained in the file LICENSE in this distribution.
97dd7cddfSDavid du Colombier
10*593dc095SDavid du Colombier For more information about licensing, please refer to
11*593dc095SDavid du Colombier http://www.ghostscript.com/licensing/. For information on
12*593dc095SDavid du Colombier commercial licensing, go to http://www.artifex.com/licensing/ or
13*593dc095SDavid du Colombier contact Artifex Software, Inc., 101 Lucas Valley Road #110,
14*593dc095SDavid du Colombier San Rafael, CA 94903, U.S.A., +1(415)492-9861.
157dd7cddfSDavid du Colombier */
167dd7cddfSDavid du Colombier
17*593dc095SDavid du Colombier /* $Id: gp_wsync.c,v 1.4 2002/02/21 22:24:52 giles Exp $ */
187dd7cddfSDavid du Colombier /* MS Windows (Win32) thread / semaphore / monitor implementation */
197dd7cddfSDavid du Colombier /* original multi-threading code by John Desrosiers */
207dd7cddfSDavid du Colombier #include "malloc_.h"
217dd7cddfSDavid du Colombier #include "gserror.h"
227dd7cddfSDavid du Colombier #include "gserrors.h"
237dd7cddfSDavid du Colombier #include "gpsync.h"
247dd7cddfSDavid du Colombier #include "windows_.h"
257dd7cddfSDavid du Colombier #include <process.h>
267dd7cddfSDavid du Colombier
277dd7cddfSDavid du Colombier /* ------- Synchronization primitives -------- */
287dd7cddfSDavid du Colombier
297dd7cddfSDavid du Colombier /* Semaphore supports wait/signal semantics */
307dd7cddfSDavid du Colombier
317dd7cddfSDavid du Colombier typedef struct win32_semaphore_s {
327dd7cddfSDavid du Colombier HANDLE handle; /* returned from CreateSemaphore */
337dd7cddfSDavid du Colombier } win32_semaphore;
347dd7cddfSDavid du Colombier
357dd7cddfSDavid du Colombier uint
gp_semaphore_sizeof(void)367dd7cddfSDavid du Colombier gp_semaphore_sizeof(void)
377dd7cddfSDavid du Colombier {
387dd7cddfSDavid du Colombier return sizeof(win32_semaphore);
397dd7cddfSDavid du Colombier }
407dd7cddfSDavid du Colombier
417dd7cddfSDavid du Colombier int /* if sema <> 0 rets -ve error, 0 ok; if sema == 0, 0 movable, 1 fixed */
gp_semaphore_open(gp_semaphore * sema)427dd7cddfSDavid du Colombier gp_semaphore_open(
437dd7cddfSDavid du Colombier gp_semaphore * sema /* create semaphore here */
447dd7cddfSDavid du Colombier )
457dd7cddfSDavid du Colombier {
467dd7cddfSDavid du Colombier win32_semaphore *const winSema = (win32_semaphore *)sema;
477dd7cddfSDavid du Colombier
487dd7cddfSDavid du Colombier if (winSema) {
497dd7cddfSDavid du Colombier winSema->handle = CreateSemaphore(NULL, 0, max_int, NULL);
507dd7cddfSDavid du Colombier return
517dd7cddfSDavid du Colombier (winSema->handle != NULL ? 0 :
527dd7cddfSDavid du Colombier gs_note_error(gs_error_unknownerror));
537dd7cddfSDavid du Colombier } else
547dd7cddfSDavid du Colombier return 0; /* Win32 semaphores handles may be moved */
557dd7cddfSDavid du Colombier }
567dd7cddfSDavid du Colombier
577dd7cddfSDavid du Colombier int
gp_semaphore_close(gp_semaphore * sema)587dd7cddfSDavid du Colombier gp_semaphore_close(
597dd7cddfSDavid du Colombier gp_semaphore * sema /* semaphore to affect */
607dd7cddfSDavid du Colombier )
617dd7cddfSDavid du Colombier {
627dd7cddfSDavid du Colombier win32_semaphore *const winSema = (win32_semaphore *)sema;
637dd7cddfSDavid du Colombier
647dd7cddfSDavid du Colombier if (winSema->handle != NULL)
657dd7cddfSDavid du Colombier CloseHandle(winSema->handle);
667dd7cddfSDavid du Colombier winSema->handle = NULL;
677dd7cddfSDavid du Colombier return 0;
687dd7cddfSDavid du Colombier }
697dd7cddfSDavid du Colombier
707dd7cddfSDavid du Colombier int /* rets 0 ok, -ve error */
gp_semaphore_wait(gp_semaphore * sema)717dd7cddfSDavid du Colombier gp_semaphore_wait(
727dd7cddfSDavid du Colombier gp_semaphore * sema /* semaphore to affect */
737dd7cddfSDavid du Colombier )
747dd7cddfSDavid du Colombier {
757dd7cddfSDavid du Colombier win32_semaphore *const winSema = (win32_semaphore *)sema;
767dd7cddfSDavid du Colombier
777dd7cddfSDavid du Colombier return
787dd7cddfSDavid du Colombier (WaitForSingleObject(winSema->handle, INFINITE) == WAIT_OBJECT_0
797dd7cddfSDavid du Colombier ? 0 : gs_error_unknownerror);
807dd7cddfSDavid du Colombier }
817dd7cddfSDavid du Colombier
827dd7cddfSDavid du Colombier int /* rets 0 ok, -ve error */
gp_semaphore_signal(gp_semaphore * sema)837dd7cddfSDavid du Colombier gp_semaphore_signal(
847dd7cddfSDavid du Colombier gp_semaphore * sema /* semaphore to affect */
857dd7cddfSDavid du Colombier )
867dd7cddfSDavid du Colombier {
877dd7cddfSDavid du Colombier win32_semaphore *const winSema = (win32_semaphore *)sema;
887dd7cddfSDavid du Colombier
897dd7cddfSDavid du Colombier return
907dd7cddfSDavid du Colombier (ReleaseSemaphore(winSema->handle, 1, NULL) ? 0 :
917dd7cddfSDavid du Colombier gs_error_unknownerror);
927dd7cddfSDavid du Colombier }
937dd7cddfSDavid du Colombier
947dd7cddfSDavid du Colombier
957dd7cddfSDavid du Colombier /* Monitor supports enter/leave semantics */
967dd7cddfSDavid du Colombier
977dd7cddfSDavid du Colombier typedef struct win32_monitor_s {
987dd7cddfSDavid du Colombier CRITICAL_SECTION lock; /* critical section lock */
997dd7cddfSDavid du Colombier } win32_monitor;
1007dd7cddfSDavid du Colombier
1017dd7cddfSDavid du Colombier uint
gp_monitor_sizeof(void)1027dd7cddfSDavid du Colombier gp_monitor_sizeof(void)
1037dd7cddfSDavid du Colombier {
1047dd7cddfSDavid du Colombier return sizeof(win32_monitor);
1057dd7cddfSDavid du Colombier }
1067dd7cddfSDavid du Colombier
1077dd7cddfSDavid du Colombier int /* if sema <> 0 rets -ve error, 0 ok; if sema == 0, 0 movable, 1 fixed */
gp_monitor_open(gp_monitor * mon)1087dd7cddfSDavid du Colombier gp_monitor_open(
1097dd7cddfSDavid du Colombier gp_monitor * mon /* create monitor here */
1107dd7cddfSDavid du Colombier )
1117dd7cddfSDavid du Colombier {
1127dd7cddfSDavid du Colombier win32_monitor *const winMon = (win32_monitor *)mon;
1137dd7cddfSDavid du Colombier
1147dd7cddfSDavid du Colombier if (mon) {
1157dd7cddfSDavid du Colombier InitializeCriticalSection(&winMon->lock); /* returns no status */
1167dd7cddfSDavid du Colombier return 0;
1177dd7cddfSDavid du Colombier } else
1187dd7cddfSDavid du Colombier return 1; /* Win32 critical sections mutsn't be moved */
1197dd7cddfSDavid du Colombier }
1207dd7cddfSDavid du Colombier
1217dd7cddfSDavid du Colombier int
gp_monitor_close(gp_monitor * mon)1227dd7cddfSDavid du Colombier gp_monitor_close(
1237dd7cddfSDavid du Colombier gp_monitor * mon /* monitor to affect */
1247dd7cddfSDavid du Colombier )
1257dd7cddfSDavid du Colombier {
1267dd7cddfSDavid du Colombier win32_monitor *const winMon = (win32_monitor *)mon;
1277dd7cddfSDavid du Colombier
1287dd7cddfSDavid du Colombier DeleteCriticalSection(&winMon->lock); /* rets no status */
1297dd7cddfSDavid du Colombier return 0;
1307dd7cddfSDavid du Colombier }
1317dd7cddfSDavid du Colombier
1327dd7cddfSDavid du Colombier int /* rets 0 ok, -ve error */
gp_monitor_enter(gp_monitor * mon)1337dd7cddfSDavid du Colombier gp_monitor_enter(
1347dd7cddfSDavid du Colombier gp_monitor * mon /* monitor to affect */
1357dd7cddfSDavid du Colombier )
1367dd7cddfSDavid du Colombier {
1377dd7cddfSDavid du Colombier win32_monitor *const winMon = (win32_monitor *)mon;
1387dd7cddfSDavid du Colombier
1397dd7cddfSDavid du Colombier EnterCriticalSection(&winMon->lock); /* rets no status */
1407dd7cddfSDavid du Colombier return 0;
1417dd7cddfSDavid du Colombier }
1427dd7cddfSDavid du Colombier
1437dd7cddfSDavid du Colombier int /* rets 0 ok, -ve error */
gp_monitor_leave(gp_monitor * mon)1447dd7cddfSDavid du Colombier gp_monitor_leave(
1457dd7cddfSDavid du Colombier gp_monitor * mon /* monitor to affect */
1467dd7cddfSDavid du Colombier )
1477dd7cddfSDavid du Colombier {
1487dd7cddfSDavid du Colombier win32_monitor *const winMon = (win32_monitor *)mon;
1497dd7cddfSDavid du Colombier
1507dd7cddfSDavid du Colombier LeaveCriticalSection(&winMon->lock); /* rets no status */
1517dd7cddfSDavid du Colombier return 0;
1527dd7cddfSDavid du Colombier }
1537dd7cddfSDavid du Colombier
1547dd7cddfSDavid du Colombier /* --------- Thread primitives ---------- */
1557dd7cddfSDavid du Colombier
1567dd7cddfSDavid du Colombier typedef struct gp_thread_creation_closure_s {
1577dd7cddfSDavid du Colombier gp_thread_creation_callback_t function; /* function to start */
1587dd7cddfSDavid du Colombier void *data; /* magic data to pass to thread */
1597dd7cddfSDavid du Colombier } gp_thread_creation_closure;
1607dd7cddfSDavid du Colombier
1617dd7cddfSDavid du Colombier /* Origin of new threads started by gp_create_thread */
1627dd7cddfSDavid du Colombier private void
gp_thread_begin_wrapper(void * thread_data)1637dd7cddfSDavid du Colombier gp_thread_begin_wrapper(
1647dd7cddfSDavid du Colombier void *thread_data /* gp_thread_creation_closure passed as magic data */
1657dd7cddfSDavid du Colombier )
1667dd7cddfSDavid du Colombier {
1677dd7cddfSDavid du Colombier gp_thread_creation_closure closure;
1687dd7cddfSDavid du Colombier
1697dd7cddfSDavid du Colombier closure = *(gp_thread_creation_closure *)thread_data;
1707dd7cddfSDavid du Colombier free(thread_data);
1717dd7cddfSDavid du Colombier (*closure.function)(closure.data);
1727dd7cddfSDavid du Colombier _endthread();
1737dd7cddfSDavid du Colombier }
1747dd7cddfSDavid du Colombier
1757dd7cddfSDavid du Colombier /* Call a function on a brand new thread */
1767dd7cddfSDavid du Colombier int /* 0 ok, -ve error */
gp_create_thread(gp_thread_creation_callback_t function,void * data)1777dd7cddfSDavid du Colombier gp_create_thread(
1787dd7cddfSDavid du Colombier gp_thread_creation_callback_t function, /* function to start */
1797dd7cddfSDavid du Colombier void *data /* magic data to pass to thread fn */
1807dd7cddfSDavid du Colombier )
1817dd7cddfSDavid du Colombier {
1827dd7cddfSDavid du Colombier /* Create the magic closure that thread_wrapper gets passed */
1837dd7cddfSDavid du Colombier gp_thread_creation_closure *closure =
1847dd7cddfSDavid du Colombier (gp_thread_creation_closure *)malloc(sizeof(*closure));
1857dd7cddfSDavid du Colombier
1867dd7cddfSDavid du Colombier if (!closure)
1877dd7cddfSDavid du Colombier return gs_error_VMerror;
1887dd7cddfSDavid du Colombier closure->function = function;
1897dd7cddfSDavid du Colombier closure->data = data;
1907dd7cddfSDavid du Colombier
1917dd7cddfSDavid du Colombier /*
1927dd7cddfSDavid du Colombier * Start thread_wrapper. The Watcom _beginthread returns (int)(-1) if
1937dd7cddfSDavid du Colombier * the call fails. The Microsoft _beginthread returns -1 (according to
1947dd7cddfSDavid du Colombier * the doc, even though the return type is "unsigned long" !!!) if the
1957dd7cddfSDavid du Colombier * call fails; we aren't sure what the Borland _beginthread returns.
1967dd7cddfSDavid du Colombier * The hack with ~ avoids a source code commitment as to whether the
1977dd7cddfSDavid du Colombier * return type is [u]int or [u]long.
1987dd7cddfSDavid du Colombier *
1997dd7cddfSDavid du Colombier * BEGIN_THREAD is a macro (defined in windows_.h) because _beginthread
2007dd7cddfSDavid du Colombier * takes different arguments in Watcom C.
2017dd7cddfSDavid du Colombier */
2027dd7cddfSDavid du Colombier if (~BEGIN_THREAD(gp_thread_begin_wrapper, 0, closure) != 0)
2037dd7cddfSDavid du Colombier return 0;
2047dd7cddfSDavid du Colombier return_error(gs_error_unknownerror);
2057dd7cddfSDavid du Colombier }
2067dd7cddfSDavid du Colombier
207