+#ifdef WIN32
+
+typedef struct _ThreadList ThreadList;
+
+struct _ThreadList
+{
+ HANDLE hThread;
+ IOCHAN pIOChannel;
+ ThreadList *pNext;
+};
+
+static ThreadList *pFirstThread;
+static CRITICAL_SECTION Thread_CritSect;
+static BOOL bInitialized = FALSE;
+
+static void ThreadList_Initialize()
+{
+ /* Initialize the critical Sections */
+ InitializeCriticalSection(&Thread_CritSect);
+
+ /* Set the first thraed */
+ pFirstThread = NULL;
+
+ /* we have been initialized */
+ bInitialized = TRUE;
+}
+
+static void statserv_add(HANDLE hThread, IOCHAN pIOChannel)
+{
+ /* Only one thread can go through this section at a time */
+ EnterCriticalSection(&Thread_CritSect);
+
+ {
+ /* Lets create our new object */
+ ThreadList *pNewThread = (ThreadList *)malloc(sizeof(ThreadList));
+ pNewThread->hThread = hThread;
+ pNewThread->pIOChannel = pIOChannel;
+ pNewThread->pNext = pFirstThread;
+ pFirstThread = pNewThread;
+
+ /* Lets let somebody else create a new object now */
+ LeaveCriticalSection(&Thread_CritSect);
+ }
+}
+
+void statserv_remove(IOCHAN pIOChannel)
+{
+ /* Only one thread can go through this section at a time */
+ EnterCriticalSection(&Thread_CritSect);
+
+ {
+ ThreadList *pCurrentThread = pFirstThread;
+ ThreadList *pNextThread;
+ ThreadList *pPrevThread =NULL;
+
+ /* Step through alll the threads */
+ for (; pCurrentThread != NULL; pCurrentThread = pNextThread)
+ {
+ /* We only need to compare on the IO Channel */
+ if (pCurrentThread->pIOChannel == pIOChannel)
+ {
+ /* We have found the thread we want to delete */
+ /* First of all reset the next pointers */
+ if (pPrevThread == NULL)
+ pFirstThread = pCurrentThread->pNext;
+ else
+ pPrevThread->pNext = pCurrentThread->pNext;
+
+ /* All we need todo now is delete the memory */
+ free(pCurrentThread);
+
+ /* No need to look at any more threads */
+ pNextThread = NULL;
+ }
+ else
+ {
+ /* We need to look at another thread */
+ pNextThread = pCurrentThread->pNext;
+ pPrevThread = pCurrentThread;
+ }
+ }
+
+ /* Lets let somebody else remove an object now */
+ LeaveCriticalSection(&Thread_CritSect);
+ }
+}
+
+void statserv_closedown()
+{
+ /* Shouldn't do anything if we are not initialized */
+ if (bInitialized)
+ {
+ int iHandles = 0;
+ HANDLE *pThreadHandles = NULL;
+
+ /* We need to stop threads adding and removing while we */
+ /* start the closedown process */
+ EnterCriticalSection(&Thread_CritSect);
+
+ {
+ /* We have exclusive access to the thread stuff now */
+ /* Y didn't i use a semaphore - Oh well never mind */
+ ThreadList *pCurrentThread = pFirstThread;
+
+ /* Before we do anything else, we need to shutdown the listener */
+ if (pListener != NULL)
+ iochan_destroy(pListener);
+
+ for (; pCurrentThread != NULL; pCurrentThread = pCurrentThread->pNext)
+ {
+ /* Just destroy the IOCHAN, that should do the trick */
+ iochan_destroy(pCurrentThread->pIOChannel);
+
+ /* Keep a running count of our handles */
+ iHandles++;
+ }
+
+ if (iHandles > 0)
+ {
+ HANDLE *pCurrentHandle ;
+
+ /* Allocate the thread handle array */
+ pThreadHandles = (HANDLE *)malloc(sizeof(HANDLE) * iHandles);
+ pCurrentHandle = pThreadHandles;
+
+ for (pCurrentThread = pFirstThread;
+ pCurrentThread != NULL;
+ pCurrentThread = pCurrentThread->pNext, pCurrentHandle++)
+ {
+ /* Just the handle */
+ *pCurrentHandle = pCurrentThread->hThread;
+ }
+ }
+
+ /* We can now leave the critical section */
+ LeaveCriticalSection(&Thread_CritSect);
+ }
+
+ /* Now we can really do something */
+ if (iHandles > 0)
+ {
+ /* This will now wait, until all the threads close */
+ WaitForMultipleObjects(iHandles, pThreadHandles, TRUE, INFINITE);
+
+ /* Free the memory we allocated for the handle array */
+ free(pThreadHandles);
+ }
+
+ if (control_block.bend_stop)
+ (*control_block.bend_stop)(&control_block);
+ /* No longer require the critical section, since all threads are dead */
+ DeleteCriticalSection(&Thread_CritSect);
+ }
+}
+
+int __stdcall event_loop_thread (IOCHAN iochan)
+{
+ return event_loop (&iochan);
+}
+
+static void listener(IOCHAN h, int event)
+{
+ COMSTACK line = (COMSTACK) iochan_getdata(h);
+ association *newas;
+ int res;
+ HANDLE NewHandle;
+
+ if (event == EVENT_INPUT)
+ {
+ if ((res = cs_listen(line, 0, 0)) < 0)
+ {
+ yaz_log(LOG_FATAL, "cs_listen failed");
+ return;
+ }
+ else if (res == 1)
+ return;
+ yaz_log(LOG_DEBUG, "listen ok");
+ iochan_setevent(h, EVENT_OUTPUT);
+ iochan_setflags(h, EVENT_OUTPUT | EVENT_EXCEPT); /* set up for acpt */
+ }
+ else if (event == EVENT_OUTPUT)
+ {
+ COMSTACK new_line;
+ IOCHAN new_chan;
+ char *a = NULL;
+ DWORD ThreadId;
+
+ if (!(new_line = cs_accept(line)))
+ {
+ yaz_log(LOG_FATAL, "Accept failed.");
+ iochan_setflags(h, EVENT_INPUT | EVENT_EXCEPT); /* reset listener */
+ return;
+ }
+ yaz_log(LOG_DEBUG, "Accept ok");
+
+ if (!(new_chan = iochan_create(cs_fileno(new_line), ir_session,
+ EVENT_INPUT)))
+ {
+ yaz_log(LOG_FATAL, "Failed to create iochan");
+ iochan_destroy(h);
+ return;
+ }
+
+ yaz_log(LOG_DEBUG, "Creating association");
+ if (!(newas = create_association(new_chan, new_line)))
+ {
+ yaz_log(LOG_FATAL, "Failed to create new assoc.");
+ iochan_destroy(h);
+ return;
+ }
+ yaz_log(LOG_DEBUG, "Setting timeout %d", control_block.idle_timeout);
+ iochan_setdata(new_chan, newas);
+ iochan_settimeout(new_chan, control_block.idle_timeout * 60);
+#ifndef WIN32
+ yaz_log(LOG_DEBUG, "Determining client address");
+ a = cs_addrstr(new_line);
+ yaz_log(LOG_LOG, "Accepted connection from %s", a ? a : "[Unknown]");
+#endif
+ /* Now what we need todo is create a new thread with this iochan as
+ the parameter */
+ /* if (CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)event_loop_thread,
+ new_chan, 0, &ThreadId) == NULL) */
+ /* Somehow, somewhere we need to store this thread id, otherwise we
+ won't be able to close cleanly */
+ NewHandle = (HANDLE)_beginthreadex(NULL, 0, event_loop_thread,
+ new_chan, 0, &ThreadId);
+ if (NewHandle == (HANDLE)-1)
+ {
+
+ yaz_log(LOG_FATAL|LOG_ERRNO, "Failed to create new thread.");
+ iochan_destroy(h);
+ return;
+ }
+ /* We successfully created the thread, so add it to the list */
+ statserv_add(NewHandle, new_chan);
+
+ yaz_log(LOG_DEBUG, "Created new thread, iochan %p", new_chan);
+ iochan_setflags(h, EVENT_INPUT | EVENT_EXCEPT); /* reset listener */
+ }
+ else
+ {
+ yaz_log(LOG_FATAL, "Bad event on listener.");
+ iochan_destroy(h);
+ return;
+ }
+}
+
+#else /* WIN32 */
+
+/* To save having an #ifdef in event_loop we need to define this empty function */
+void statserv_remove(IOCHAN pIOChannel)
+{
+}
+
+void statserv_closedown()
+{
+ IOCHAN p;
+ for (p = pListener; p; p = p->next)
+ iochan_destroy(p);
+}
+