summaryrefslogtreecommitdiffstats
path: root/otherlibs/win32unix
diff options
context:
space:
mode:
Diffstat (limited to 'otherlibs/win32unix')
-rw-r--r--otherlibs/win32unix/windbug.c32
-rw-r--r--otherlibs/win32unix/windbug.h50
-rw-r--r--otherlibs/win32unix/winlist.c80
-rw-r--r--otherlibs/win32unix/winlist.h54
-rw-r--r--otherlibs/win32unix/winworker.c338
-rw-r--r--otherlibs/win32unix/winworker.h70
6 files changed, 624 insertions, 0 deletions
diff --git a/otherlibs/win32unix/windbug.c b/otherlibs/win32unix/windbug.c
new file mode 100644
index 000000000..a6fd35e8d
--- /dev/null
+++ b/otherlibs/win32unix/windbug.c
@@ -0,0 +1,32 @@
+/***********************************************************************/
+/* */
+/* Objective Caml */
+/* */
+/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
+/* */
+/* Copyright 1996 Institut National de Recherche en Informatique et */
+/* en Automatique. All rights reserved. This file is distributed */
+/* under the terms of the GNU Library General Public License, with */
+/* the special exception on linking described in file ../../LICENSE. */
+/* */
+/***********************************************************************/
+
+/* $Id$ */
+
+#include <windows.h>
+
+int dbug = 0;
+
+void dbug_init (void)
+{
+ dbug = (getenv("OCAMLDBUG") != NULL);
+}
+
+void dbug_cleanup (void)
+{
+}
+
+int dbug_test (void)
+{
+ return dbug;
+}
diff --git a/otherlibs/win32unix/windbug.h b/otherlibs/win32unix/windbug.h
new file mode 100644
index 000000000..5ac5ca538
--- /dev/null
+++ b/otherlibs/win32unix/windbug.h
@@ -0,0 +1,50 @@
+/***********************************************************************/
+/* */
+/* Objective Caml */
+/* */
+/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
+/* */
+/* Copyright 1996 Institut National de Recherche en Informatique et */
+/* en Automatique. All rights reserved. This file is distributed */
+/* under the terms of the GNU Library General Public License, with */
+/* the special exception on linking described in file ../../LICENSE. */
+/* */
+/***********************************************************************/
+
+/* $Id$ */
+
+/*#define DBUG*/
+
+#ifdef DBUG
+
+#include <stdio.h>
+#include <windows.h>
+
+#define DBUG_PRINT(fmt, ...) \
+ do \
+ { \
+ if (dbug_test()) \
+ { \
+ fprintf(stderr, "DBUG (pid:%d, tid: %d): ", GetCurrentProcessId(), GetCurrentThreadId()); \
+ fprintf(stderr, fmt, __VA_ARGS__); \
+ fprintf(stderr, "\n"); \
+ fflush(stderr); \
+ }; \
+ } while(0)
+
+/* Initialize and cleanup dbug variable */
+void dbug_init (void);
+void dbug_cleanup (void);
+
+/* Test if we are in dbug mode */
+int dbug_test (void);
+
+#define DBUG_INIT dbug_init()
+#define DBUG_CLEANUP dbug_cleanup()
+
+#else
+#define DBUG_PRINT(fmt, ...)
+#define DBUG_INIT
+#define DBUG_CLEANUP
+#endif
+
diff --git a/otherlibs/win32unix/winlist.c b/otherlibs/win32unix/winlist.c
new file mode 100644
index 000000000..756b326e2
--- /dev/null
+++ b/otherlibs/win32unix/winlist.c
@@ -0,0 +1,80 @@
+/***********************************************************************/
+/* */
+/* Objective Caml */
+/* */
+/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
+/* */
+/* Copyright 1996 Institut National de Recherche en Informatique et */
+/* en Automatique. All rights reserved. This file is distributed */
+/* under the terms of the GNU Library General Public License, with */
+/* the special exception on linking described in file ../../LICENSE. */
+/* */
+/***********************************************************************/
+
+/* $Id$ */
+
+/* Basic list function in C. */
+
+#include "winlist.h"
+#include <windows.h>
+
+void list_init (LPLIST lst)
+{
+ lst->lpNext = NULL;
+}
+
+void list_cleanup (LPLIST lst)
+{
+ lst->lpNext = NULL;
+}
+
+void list_next_set (LPLIST lst, LPLIST next)
+{
+ lst->lpNext = next;
+}
+
+LPLIST list_next (LPLIST lst)
+{
+ return lst->lpNext;
+}
+
+int list_length (LPLIST lst)
+{
+ int length = 0;
+ LPLIST iter = lst;
+ while (iter != NULL)
+ {
+ length++;
+ iter = list_next(iter);
+ };
+ return length;
+}
+
+LPLIST list_concat (LPLIST lsta, LPLIST lstb)
+{
+ LPLIST res = NULL;
+ LPLIST iter = NULL;
+ LPLIST iterPrev = NULL;
+
+ if (lsta == NULL)
+ {
+ res = lstb;
+ }
+ else if (lstb == NULL)
+ {
+ res = lsta;
+ }
+ else
+ {
+ res = lsta;
+ iter = lsta;
+ while (iter != NULL)
+ {
+ iterPrev = iter;
+ iter = list_next(iter);
+ };
+ iterPrev->lpNext = lstb;
+ };
+
+ return res;
+}
diff --git a/otherlibs/win32unix/winlist.h b/otherlibs/win32unix/winlist.h
new file mode 100644
index 000000000..3c96513a2
--- /dev/null
+++ b/otherlibs/win32unix/winlist.h
@@ -0,0 +1,54 @@
+/***********************************************************************/
+/* */
+/* Objective Caml */
+/* */
+/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
+/* */
+/* Copyright 1996 Institut National de Recherche en Informatique et */
+/* en Automatique. All rights reserved. This file is distributed */
+/* under the terms of the GNU Library General Public License, with */
+/* the special exception on linking described in file ../../LICENSE. */
+/* */
+/***********************************************************************/
+
+/* $Id$ */
+#ifndef _WINLIST_H
+#define _WINLIST_H
+
+/* Basic list function in C. */
+
+/* Singly-linked list data structure.
+ * To transform a C struct into a list structure, you must include
+ * at first position of your C struct a "LIST lst" and call list_init
+ * on this data structure.
+ *
+ * See winworker.c for example.
+ */
+typedef struct _LIST LIST;
+typedef LIST *LPLIST;
+
+struct _LIST {
+ LPLIST lpNext;
+};
+
+/* Initialize list data structure */
+void list_init (LPLIST lst);
+
+/* Cleanup list data structure */
+void list_cleanup (LPLIST lst);
+
+/* Set next element */
+void list_next_set (LPLIST lst, LPLIST next);
+
+/* Return next element */
+LPLIST list_next (LPLIST);
+
+#define LIST_NEXT(T, e) ((T)(list_next((LPLIST)(e))))
+
+/* Get number of element */
+int list_length (LPLIST);
+
+/* Concat two list. */
+LPLIST list_concat (LPLIST, LPLIST);
+
+#endif /* _WINLIST_H */
diff --git a/otherlibs/win32unix/winworker.c b/otherlibs/win32unix/winworker.c
new file mode 100644
index 000000000..fb8cde979
--- /dev/null
+++ b/otherlibs/win32unix/winworker.c
@@ -0,0 +1,338 @@
+/***********************************************************************/
+/* */
+/* Objective Caml */
+/* */
+/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
+/* */
+/* Copyright 1996 Institut National de Recherche en Informatique et */
+/* en Automatique. All rights reserved. This file is distributed */
+/* under the terms of the GNU Library General Public License, with */
+/* the special exception on linking described in file ../../LICENSE. */
+/* */
+/***********************************************************************/
+
+/* $Id$ */
+
+#include "winworker.h"
+#include "winlist.h"
+#include "windbug.h"
+#include <mlvalues.h>
+#include <alloc.h>
+#include "unixsupport.h"
+
+typedef enum {
+ WORKER_CMD_NONE = 0,
+ WORKER_CMD_EXEC,
+ WORKER_CMD_STOP
+} WORKERCMD;
+
+struct _WORKER {
+ LIST lst; /* This structure is used as a list. */
+ HANDLE hJobStarted; /* Event representing that the function has begun. */
+ HANDLE hJobStop; /* Event that can be used to notify the function that it
+ should stop processing. */
+ HANDLE hJobDone; /* Event representing that the function has finished. */
+ void *lpJobUserData; /* User data for the job. */
+ WORKERFUNC hJobFunc; /* Function to be called during APC */
+ HANDLE hWorkerReady; /* Worker is ready. */
+ HANDLE hCommandReady; /* Worker should execute command. */
+ WORKERCMD ECommand; /* Command to execute */
+ HANDLE hThread; /* Thread handle of the worker. */
+};
+
+#define THREAD_WORKERS_MAX 16
+#define THREAD_WORKERS_MEM 4000
+
+LPWORKER lpWorkers = NULL;
+DWORD nWorkersCurrent = 0;
+DWORD nWorkersMax = 0;
+HANDLE hWorkersMutex = INVALID_HANDLE_VALUE;
+HANDLE hWorkerHeap = INVALID_HANDLE_VALUE;
+
+DWORD WINAPI worker_wait (LPVOID _data)
+{
+ BOOL bExit;
+ LPWORKER lpWorker;
+
+ lpWorker = (LPWORKER )_data;
+ bExit = FALSE;
+
+ DBUG_PRINT("Worker %x starting", lpWorker);
+ while (
+ !bExit
+ && SignalObjectAndWait(
+ lpWorker->hWorkerReady,
+ lpWorker->hCommandReady,
+ INFINITE,
+ TRUE) == WAIT_OBJECT_0)
+ {
+ DBUG_PRINT("Worker %x running", lpWorker);
+ switch (lpWorker->ECommand)
+ {
+ case WORKER_CMD_NONE:
+ break;
+
+ case WORKER_CMD_EXEC:
+ if (lpWorker->hJobFunc != NULL)
+ {
+ SetEvent(lpWorker->hJobStarted);
+ lpWorker->hJobFunc(lpWorker->hJobStop, lpWorker->lpJobUserData);
+ SetEvent(lpWorker->hJobDone);
+ };
+ break;
+
+ case WORKER_CMD_STOP:
+ bExit = TRUE;
+ break;
+ }
+ };
+ DBUG_PRINT("Worker %x exiting", lpWorker);
+
+ return 0;
+}
+
+LPWORKER worker_new (void)
+{
+ LPWORKER lpWorker = NULL;
+
+ if (!HeapLock(hWorkerHeap))
+ {
+ win32_maperr(GetLastError());
+ uerror("worker_new", Nothing);
+ };
+ lpWorker = (LPWORKER)HeapAlloc(hWorkerHeap, 0, sizeof(WORKER));
+ HeapUnlock(hWorkerHeap);
+ list_init((LPLIST)lpWorker);
+ lpWorker->hJobStarted = CreateEvent(NULL, TRUE, FALSE, NULL);
+ lpWorker->hJobStop = CreateEvent(NULL, TRUE, FALSE, NULL);
+ lpWorker->hJobDone = CreateEvent(NULL, TRUE, FALSE, NULL);
+ lpWorker->lpJobUserData = NULL;
+ lpWorker->hWorkerReady = CreateEvent(NULL, FALSE, FALSE, NULL);
+ lpWorker->hCommandReady = CreateEvent(NULL, FALSE, FALSE, NULL);
+ lpWorker->ECommand = WORKER_CMD_NONE;
+ lpWorker->hThread = CreateThread(
+ NULL,
+ THREAD_WORKERS_MEM,
+ worker_wait,
+ (LPVOID)lpWorker,
+ 0,
+ NULL);
+
+ return lpWorker;
+};
+
+void worker_free (LPWORKER lpWorker)
+{
+ /* Wait for termination of the worker */
+ DBUG_PRINT("Shutting down worker %x", lpWorker);
+ WaitForSingleObject(lpWorker->hWorkerReady, INFINITE);
+ lpWorker->ECommand = WORKER_CMD_STOP;
+ SetEvent(lpWorker->hCommandReady);
+ WaitForSingleObject(lpWorker->hThread, INFINITE);
+
+ /* Free resources */
+ DBUG_PRINT("Freeing resources of worker %x", lpWorker);
+ if (lpWorker->hThread != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(lpWorker->hThread);
+ lpWorker->hThread = INVALID_HANDLE_VALUE;
+ }
+
+ if (lpWorker->hJobStarted != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(lpWorker->hJobStarted);
+ lpWorker->hJobStarted = INVALID_HANDLE_VALUE;
+ }
+
+ if (lpWorker->hJobStop != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(lpWorker->hJobStop);
+ lpWorker->hJobStop = INVALID_HANDLE_VALUE;
+ }
+
+ if (lpWorker->hJobDone != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(lpWorker->hJobDone);
+ lpWorker->hJobDone = INVALID_HANDLE_VALUE;
+ }
+
+ lpWorker->lpJobUserData = NULL;
+ lpWorker->hJobFunc = NULL;
+
+ if (lpWorker->hWorkerReady != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(lpWorker->hWorkerReady);
+ lpWorker->hWorkerReady = INVALID_HANDLE_VALUE;
+ }
+
+ if (lpWorker->hCommandReady != INVALID_HANDLE_VALUE)
+ {
+ CloseHandle(lpWorker->hCommandReady);
+ lpWorker->hCommandReady = INVALID_HANDLE_VALUE;
+ }
+
+ if (!HeapLock(hWorkerHeap))
+ {
+ win32_maperr(GetLastError());
+ uerror("worker_new", Nothing);
+ };
+ HeapFree(hWorkerHeap, 0, lpWorker);
+ HeapUnlock(hWorkerHeap);
+};
+
+LPWORKER worker_pop (void)
+{
+ LPWORKER lpWorkerFree = NULL;
+
+ WaitForSingleObject(hWorkersMutex, INFINITE);
+ /* Get the first worker of the list */
+ if (lpWorkers != NULL)
+ {
+ lpWorkerFree = lpWorkers;
+ lpWorkers = LIST_NEXT(LPWORKER, lpWorkers);
+ }
+ nWorkersCurrent++;
+ nWorkersMax = (nWorkersCurrent > nWorkersMax ? nWorkersCurrent : nWorkersMax);
+ DBUG_PRINT("Workers running current/runnning max/waiting: %d/%d/%d",
+ nWorkersCurrent,
+ nWorkersMax,
+ list_length((LPLIST)lpWorkers));
+ ReleaseMutex(hWorkersMutex);
+
+ if (lpWorkerFree == NULL)
+ {
+ /* We cannot find a free worker, create one. */
+ lpWorkerFree = worker_new();
+ }
+
+ /* Ensure that we don't get dangling pointer to old data. */
+ list_init((LPLIST)lpWorkerFree);
+ lpWorkerFree->lpJobUserData = NULL;
+
+ /* Reset events */
+ ResetEvent(lpWorkerFree->hJobStarted);
+ ResetEvent(lpWorkerFree->hJobStop);
+ ResetEvent(lpWorkerFree->hJobDone);
+
+ return lpWorkerFree;
+}
+
+void worker_push(LPWORKER lpWorker)
+{
+ BOOL bFreeWorker;
+
+ bFreeWorker = TRUE;
+
+ WaitForSingleObject(hWorkersMutex, INFINITE);
+ DBUG_PRINT("Testing if we are under the maximum number of running workers");
+ if (list_length((LPLIST)lpWorkers) < THREAD_WORKERS_MAX)
+ {
+ DBUG_PRINT("Saving this worker for future use");
+ DBUG_PRINT("Next: %x", ((LPLIST)lpWorker)->lpNext);
+ lpWorkers = (LPWORKER)list_concat((LPLIST)lpWorker, (LPLIST)lpWorkers);
+ bFreeWorker = FALSE;
+ };
+ nWorkersCurrent--;
+ DBUG_PRINT("Workers running current/runnning max/waiting: %d/%d/%d",
+ nWorkersCurrent,
+ nWorkersMax,
+ list_length((LPLIST)lpWorkers));
+ ReleaseMutex(hWorkersMutex);
+
+ if (bFreeWorker)
+ {
+ DBUG_PRINT("Freeing worker %x", lpWorker);
+ worker_free(lpWorker);
+ }
+}
+
+void worker_init (void)
+{
+ int i = 0;
+
+ /* Init a shared variable. The only way to ensure that no other
+ worker will be at the same point is to use a critical section.
+ */
+ DBUG_PRINT("Allocating mutex for workers");
+ if (hWorkersMutex == INVALID_HANDLE_VALUE)
+ {
+ hWorkersMutex = CreateMutex(NULL, FALSE, NULL);
+ }
+
+ if (hWorkerHeap == INVALID_HANDLE_VALUE)
+ {
+ hWorkerHeap = HeapCreate(0, sizeof(WORKER) * THREAD_WORKERS_MAX * 4, 0);
+ }
+}
+
+void worker_cleanup(void)
+{
+ LPWORKER lpWorker = NULL;
+
+ /* WARNING: we can have a race condition here, if while this code
+ is executed another worker is waiting to access hWorkersMutex,
+ he will never be able to get it...
+ */
+ if (hWorkersMutex != INVALID_HANDLE_VALUE)
+ {
+ WaitForSingleObject(hWorkersMutex, INFINITE);
+ DBUG_PRINT("Freeing global resource of workers");
+ /* Empty the queue of worker worker */
+ while (lpWorkers != NULL)
+ {
+ ReleaseMutex(hWorkersMutex);
+ lpWorker = worker_pop();
+ DBUG_PRINT("Freeing worker %x", lpWorker);
+ WaitForSingleObject(hWorkersMutex, INFINITE);
+ worker_free(lpWorker);
+ };
+ ReleaseMutex(hWorkersMutex);
+
+ /* Destroy associated mutex */
+ CloseHandle(hWorkersMutex);
+ hWorkersMutex = INVALID_HANDLE_VALUE;
+ };
+}
+
+LPWORKER worker_job_submit (WORKERFUNC f, void *user_data)
+{
+ LPWORKER lpWorker = worker_pop();
+
+ DBUG_PRINT("Waiting for worker to be ready");
+ enter_blocking_section();
+ WaitForSingleObject(lpWorker->hWorkerReady, INFINITE);
+ ResetEvent(lpWorker->hWorkerReady);
+ leave_blocking_section();
+ DBUG_PRINT("Worker is ready");
+
+ lpWorker->hJobFunc = f;
+ lpWorker->lpJobUserData = user_data;
+ lpWorker->ECommand = WORKER_CMD_EXEC;
+
+ DBUG_PRINT("Call worker (func: %x, worker: %x)", f, lpWorker);
+ SetEvent(lpWorker->hCommandReady);
+
+ return (LPWORKER)lpWorker;
+}
+
+HANDLE worker_job_event_done (LPWORKER lpWorker)
+{
+ return lpWorker->hJobDone;
+}
+
+void worker_job_stop (LPWORKER lpWorker)
+{
+ DBUG_PRINT("Sending stop signal to worker %x", lpWorker);
+ SetEvent(lpWorker->hJobStop);
+ DBUG_PRINT("Signal sent to worker %x", lpWorker);
+}
+
+void worker_job_finish (LPWORKER lpWorker)
+{
+ DBUG_PRINT("Finishing call of worker %x", lpWorker);
+ enter_blocking_section();
+ WaitForSingleObject(lpWorker->hJobDone, INFINITE);
+ leave_blocking_section();
+
+ worker_push(lpWorker);
+}
diff --git a/otherlibs/win32unix/winworker.h b/otherlibs/win32unix/winworker.h
new file mode 100644
index 000000000..a9e077e79
--- /dev/null
+++ b/otherlibs/win32unix/winworker.h
@@ -0,0 +1,70 @@
+/***********************************************************************/
+/* */
+/* Objective Caml */
+/* */
+/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
+/* */
+/* Copyright 1996 Institut National de Recherche en Informatique et */
+/* en Automatique. All rights reserved. This file is distributed */
+/* under the terms of the GNU Library General Public License, with */
+/* the special exception on linking described in file ../../LICENSE. */
+/* */
+/***********************************************************************/
+
+/* $Id$ */
+#ifndef _WINWORKER_H
+#define _WINWORKER_H
+
+#define _WIN32_WINNT 0x0400
+#include <windows.h>
+
+/* Pool of worker threads.
+ *
+ * These functions help to manage a pool of worker thread and submit task to
+ * the pool. It helps to reduce the number of thread creation.
+ *
+ * Each worker are started in alertable wait state and jobs are submitted as
+ * APC (asynchronous procedure call).
+ */
+
+/* Data associated with submitted job */
+typedef struct _WORKER WORKER;
+typedef WORKER *LPWORKER;
+
+/* Function type of submitted job:
+ * void worker_call (HANDLE hStop, void *data)
+ *
+ * This function will be called using the data following:
+ * - hStop must be watched for change, since it represents an external command
+ * to stop the call. This event is shared through the WORKER structure, which
+ * can be access throuhg worker_job_event_done.
+ * - data is user provided data for the function.
+ */
+typedef void (*WORKERFUNC) (HANDLE, void *);
+
+/* Initialize global data structure for worker
+ */
+void worker_init (void);
+
+/* Free global data structure for worker
+ */
+void worker_cleanup (void);
+
+/* Submit a job to worker. Use returned data to synchronize with the procedure
+ * submitted.
+ */
+LPWORKER worker_job_submit (WORKERFUNC f, void *data);
+
+/* Get event to know when a job is done.
+ */
+HANDLE worker_job_event_done (LPWORKER);
+
+/* Ask a job to stop processing.
+ */
+void worker_job_stop (LPWORKER);
+
+/* End a job submitted to worker.
+ */
+void worker_job_finish (LPWORKER);
+
+#endif /* _WINWORKER_H */