]> git.pond.sub.org Git - empserver/blob - src/lib/empthread/ntthread.c
(daemon, daemonize): Rename to avoid name clash with BSD's daemon().
[empserver] / src / lib / empthread / ntthread.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2004, Dave Pare, Jeff Bailey, Thomas Ruschak,
4  *                           Ken Stevens, Steve McClure
5  *
6  *  This program is free software; you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation; either version 2 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  *  ---
21  *
22  *  See the "LEGAL", "LICENSE", "CREDITS" and "README" files for all the
23  *  related information and legal notices. It is expected that any future
24  *  projects/authors will amend these files as needed.
25  *
26  *  ---
27  *
28  *  ntthread.c: Interface from Empire threads to Windows NT threads
29  * 
30  *  Known contributors to this file:
31  *     Doug Hay, 1998
32  *     Steve McClure, 1998
33  */
34
35 /*
36  * EMPTHREADs for Windows NT.
37  *
38  * Actually, threads for any Win32 platform,
39  * like Win95, Win98, WinCE, and whatever other
40  * toy OSs are in our future from Microsoft.
41  *
42  * WIN32 has a full pre-emptive threading environment.
43  * But, Empire can not handle pre-emptive threading.
44  * Thus, we will use the threads, but limit the preemption
45  * using a Mutex semaphore.
46  *
47  */
48
49 #include <stdio.h>
50 #include <sys/types.h>
51 #include <signal.h>
52 #include <errno.h>
53 #include "misc.h"
54 #include "empthread.h"
55 #include "prototypes.h"
56
57 #if defined(_WIN32) && defined(_EMPTH_WIN32)
58 #include <winsock2.h>
59 #include <windows.h>
60 #include <process.h>
61
62
63 #define loc_MIN_THREAD_STACK  16384
64
65 /************************
66  * loc_Thread_t
67  *
68  * The REAL empth_t thread structure.
69  * The external world only gets
70  * a void pointer to this.
71  */
72 typedef struct loc_Thread_t {
73
74     /* The thread name, passed in at create time. */
75     char szName[17];
76     /* The thread description, passed in at create time. */
77     char szDesc[80];
78
79     /* True if this is the main line, and not a real thread. */
80     BOOL bMainThread;
81
82     /* The user data passed in at create time. */
83     void *pvUserData;
84
85     /* True if this thread has been killed. */
86     BOOL bKilled;
87
88     /* The entry function for the thread. */
89     void (*pfnEntry) (void *);
90
91     /* The system thread ID. */
92     unsigned long ulThreadID;
93
94     /* An Event sem that the thread will wait/sleep on. */
95     HANDLE hThreadEvent;
96 } loc_Thread_t;
97
98
99 /************************
100  * loc_Sem_t
101  *
102  * The REAL empth_sem_t structure.
103  * The external world only gets
104  * a void pointer to this.
105  */
106 typedef struct empth_sem_t {
107
108     char szName[17];
109
110     /* An exclusion semaphore for this sem. */
111     HANDLE hMutex;
112     /* An Event sem that the thread(s) will sleep on. */
113
114     HANDLE hEvent;
115     /* The count variable */
116     int count;
117 } loc_Sem_t;
118
119 static struct {
120     /* This is the thread exclusion/non-premption mutex. */
121     /* The running thread has this MUTEX, and all others are */
122     /* either blocked on it, or waiting for some OS response. */
123     HANDLE hThreadMutex;
124
125     /* This is the thread startup event sem. */
126     /* We use this to lockstep when we are starting up threads. */
127     HANDLE hThreadStartEvent;
128
129     /* The Thread Local Storage index.  We store the pThread pointer */
130     /* for each thread at this index. */
131     DWORD dwTLSIndex;
132
133     /* The current running thread. */
134     loc_Thread_t *pCurThread;
135
136     /* Ticks at start */
137     unsigned long ulTickAtStart;
138
139     /* Pointer out to global context.  "player". */
140     /* From empth_init parameter. */
141     char **ppvUserData;
142
143     /* Global flags.  From empth_init parameter. */
144     int flags;
145 } loc_GVAR;
146
147
148 /************************
149  * loc_debug
150  *
151  * Print out the current thread's status??
152  */
153 static void
154 loc_debug(const char *pszFmt, ...)
155 {
156     va_list vaList;
157     unsigned long ulCurTick;
158     unsigned long ulRunTick;
159     unsigned long ulMs, ulSec, ulMin, ulHr;
160     loc_Thread_t *pThread =
161         (loc_Thread_t *)TlsGetValue(loc_GVAR.dwTLSIndex);
162     char buf[1024];
163
164     if ((loc_GVAR.flags & EMPTH_PRINT) != 0) {
165
166         /* Ticks are in milliseconds */
167         ulCurTick = GetTickCount();
168
169         ulRunTick = ulCurTick - loc_GVAR.ulTickAtStart;
170         ulMs = ulRunTick % 1000L;
171         ulSec = (ulRunTick / 1000L) % 60L;
172         ulMin = (ulRunTick / (60L * 1000L)) % 60L;
173         ulHr = (ulRunTick / (60L * 60L * 1000L));
174
175         va_start(vaList, pszFmt);
176         vsprintf(buf, pszFmt, vaList);
177         va_end(vaList);
178
179         if (pThread) {
180             printf("%ld:%02ld:%02ld.%03ld %17s: %s\n",
181                    ulHr, ulMin, ulSec, ulMs, pThread->szName, buf);
182         } else {
183             printf("%ld:%02ld:%02ld.%03ld %17s: %s\n",
184                    ulHr, ulMin, ulSec, ulMs, "UNKNOWN", buf);
185         }
186
187     }
188 }
189
190 /************************
191  * loc_FreeThreadInfo
192  *
193  */
194 static void
195 loc_FreeThreadInfo(loc_Thread_t *pThread)
196 {
197     if (pThread) {
198         if (pThread->hThreadEvent)
199             CloseHandle(pThread->hThreadEvent);
200         memset(pThread, 0, sizeof(*pThread));
201         free(pThread);
202     }
203 }
204
205 /************************
206  * loc_RunThisThread
207  *
208  * This thread wants to run.
209  * When this function returns, the
210  * globals are set to this thread info,
211  * and the thread owns the MUTEX sem.
212  */
213 static void
214 loc_RunThisThread()
215 {
216     loc_Thread_t *pThread =
217         (loc_Thread_t *)TlsGetValue(loc_GVAR.dwTLSIndex);
218
219     if (pThread->bKilled) {
220         if (!pThread->bMainThread) {
221             TlsSetValue(loc_GVAR.dwTLSIndex, NULL);
222             loc_FreeThreadInfo(pThread);
223             _endthread();
224         }
225     }
226
227     /* Get the MUTEX semaphore, wait forever. */
228     WaitForSingleObject(loc_GVAR.hThreadMutex, INFINITE);
229
230     if (!loc_GVAR.pCurThread) {
231         /* Set the globals to this thread. */
232         *loc_GVAR.ppvUserData = pThread->pvUserData;
233
234         loc_GVAR.pCurThread = pThread;
235     } else {
236         /* Hmm, a problem, eh? */
237         logerror("RunThisThread, someone already running.");
238     }
239 }
240
241 /************************
242  * loc_BlockThisThread
243  *
244  * This thread was running.  It no longer wants to.
245  */
246 static void
247 loc_BlockThisThread()
248 {
249     loc_Thread_t *pThread =
250         (loc_Thread_t *)TlsGetValue(loc_GVAR.dwTLSIndex);
251
252     if (loc_GVAR.pCurThread == pThread) {
253         /* Reset the globals back to original */
254
255         loc_GVAR.pCurThread = NULL;
256         *loc_GVAR.ppvUserData = NULL;
257
258         /* Release the MUTEX */
259         ReleaseMutex(loc_GVAR.hThreadMutex);
260     } else {
261         /* Hmm, this thread was not the running one. */
262         logerror("BlockThisThread, not running.");
263     }
264 }
265
266
267 /************************
268  * loc_SleepThisThread
269  */
270 static void
271 loc_SleepThisThread(unsigned long ulMillisecs)
272 {
273     loc_Thread_t *pThread =
274         (loc_Thread_t *)TlsGetValue(loc_GVAR.dwTLSIndex);
275
276     /* Make sure the event thread is clean. */
277     ResetEvent(pThread->hThreadEvent);
278
279     /* Get the MUTEX semaphore, wait the number of MS */
280     WaitForSingleObject(pThread->hThreadEvent, ulMillisecs);
281 }
282
283
284 /************************
285  * empth_threadMain
286  *
287  * This is the main line of each thread.
288  * This is really a static local func....
289  */
290 void
291 empth_threadMain(void *pvData)
292 {
293     time_t now;
294
295     loc_Thread_t *pThread = (loc_Thread_t *)pvData;
296
297     /* Out of here... */
298     if (!pvData)
299         return;
300
301     /* Store pThread on this thread. */
302     TlsSetValue(loc_GVAR.dwTLSIndex, pvData);
303
304     /* Get the ID of the thread. */
305     pThread->ulThreadID = GetCurrentThreadId();
306
307     /* Signal that the thread has started. */
308     SetEvent(loc_GVAR.hThreadStartEvent);
309
310     /* seed the rand() function */
311     time(&now);
312     srand(now ^ (unsigned int)pThread);
313
314     /* Switch to this thread context */
315     loc_RunThisThread();
316
317     /* Run the thread. */
318     if (pThread->pfnEntry)
319         pThread->pfnEntry(pThread->pvUserData);
320
321     /* Kill the thread. */
322     empth_exit();
323 }
324
325 /************************
326  * empth_init
327  *
328  * Initialize the thread environment.
329  *
330  * This is called from the program
331  * main line.
332  */
333 int
334 empth_init(char **ctx_ptr, int flags)
335 {
336     loc_Thread_t *pThread = NULL;
337
338     loc_GVAR.ulTickAtStart = GetTickCount();
339     loc_GVAR.ppvUserData = ctx_ptr;
340     loc_GVAR.flags = flags;
341     loc_GVAR.dwTLSIndex = TlsAlloc();
342
343     /* Create the thread mutex sem. */
344     /* Initally unowned. */
345     loc_GVAR.hThreadMutex = CreateMutex(NULL, FALSE, NULL);
346     if (!loc_GVAR.hThreadMutex) {
347         logerror("Failed to create mutex");
348         return 0;
349     }
350
351     /* Create the thread start event sem. */
352     /* Automatic state reset. */
353     loc_GVAR.hThreadStartEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
354     if (!loc_GVAR.hThreadStartEvent) {
355         logerror("Failed to create mutex");
356         return 0;
357     }
358
359     /* Create the global Thread context. */
360     pThread = (loc_Thread_t *)malloc(sizeof(*pThread));
361     if (!pThread) {
362         logerror("not enough memory to create main thread.");
363         return 0;
364     }
365     memset(pThread, 0, sizeof(*pThread));
366
367     strncpy(pThread->szName, "Main", sizeof(pThread->szName) - 1);
368     strncpy(pThread->szDesc, "The main process",
369             sizeof(pThread->szDesc) - 1);
370     pThread->ulThreadID = GetCurrentThreadId();
371     pThread->bMainThread = TRUE;
372
373     TlsSetValue(loc_GVAR.dwTLSIndex, pThread);
374
375     /* Make this the running thread. */
376     loc_RunThisThread();
377
378     logerror("NT pthreads initialized");
379     return 0;
380 }
381
382
383 /************************
384  * empth_create
385  *
386  * Create a new thread.
387  *
388  * prio  - priority, not particularly useful in our context.
389  * entry - entry point function for thread.
390  * size  - stack size.
391  * flags - debug control.
392  *           LWP_STACKCHECK  - not needed
393  * name  - name of the thread, for debug.
394  * desc  - description of thread, for debug.
395  * ud    - "user data".  The "ctx_ptr" gets this value
396  *         when the thread is active.
397  *         It is also passed to the entry function...
398  */
399 empth_t *
400 empth_create(int prio, void (*entry)(void *), int size, int flags,
401              char *name, char *desc, void *ud)
402 {
403     loc_Thread_t *pThread = NULL;
404
405     loc_debug("creating new thread %s:%s", name, desc);
406
407     pThread = (loc_Thread_t *)malloc(sizeof(*pThread));
408     if (!pThread) {
409         logerror("not enough memory to create thread: %s (%s)", name,
410                  desc);
411         return NULL;
412     }
413     memset(pThread, 0, sizeof(*pThread));
414
415     strncpy(pThread->szName, name, sizeof(pThread->szName) - 1);
416     strncpy(pThread->szDesc, desc, sizeof(pThread->szDesc) - 1);
417     pThread->pvUserData = ud;
418     pThread->pfnEntry = entry;
419     pThread->bMainThread = FALSE;
420
421     /* Create thread event sem, auto reset. */
422     pThread->hThreadEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
423
424     if (size < loc_MIN_THREAD_STACK)
425         size = loc_MIN_THREAD_STACK;
426
427     pThread->ulThreadID = _beginthread(empth_threadMain, size,
428                                        (void *)pThread);
429     if (pThread->ulThreadID == -1) {
430         logerror("can not create thread: %s (%s): %s", name, desc,
431                  strerror(errno));
432         goto bad;
433     }
434
435     loc_debug("new thread id is %ld", pThread->ulThreadID);
436     return pThread;
437
438   bad:
439     if (pThread) {
440         loc_FreeThreadInfo(pThread);
441     }
442     return NULL;
443 }
444
445
446 /************************
447  * empth_self
448  */
449 empth_t *
450 empth_self(void)
451 {
452     loc_Thread_t *pThread =
453         (loc_Thread_t *)TlsGetValue(loc_GVAR.dwTLSIndex);
454
455     return pThread;
456 }
457
458 /************************
459  * empth_exit
460  */
461 void
462 empth_exit(void)
463 {
464     loc_Thread_t *pThread =
465         (loc_Thread_t *)TlsGetValue(loc_GVAR.dwTLSIndex);
466
467     loc_BlockThisThread();
468
469     loc_debug("empth_exit");
470
471     if (pThread->bMainThread) {
472         /* The main line.  Wait forever. */
473         while (1) {
474             if (daemonize) {
475                 if (service_stopped())
476                     shutdwn(0);
477                 Sleep(3);
478             } else {
479                 char buf[20];
480                 printf("\nEmpire Server>");
481                 fgets(buf, sizeof(buf), stdin);
482                 if (!strnicmp(buf, "quit", 4))
483                     shutdwn(0);
484             }
485         }
486     } else {
487         TlsSetValue(loc_GVAR.dwTLSIndex, NULL);
488         loc_FreeThreadInfo(pThread);
489         _endthread();
490     }
491 }
492
493 /************************
494  * empth_yield
495  *
496  * Yield processing to another thread.
497  */
498 void
499 empth_yield(void)
500 {
501     loc_BlockThisThread();
502     loc_RunThisThread();
503 }
504
505 /************************
506  * empth_terminate
507  *
508  * Kill off the thread.
509  */
510 void
511 empth_terminate(empth_t *a)
512 {
513     loc_Thread_t *pThread = (loc_Thread_t *)a;
514
515     loc_debug("killing thread %s", pThread->szName);
516     pThread->bKilled = TRUE;
517
518     SetEvent(pThread->hThreadEvent);
519 }
520
521 /************************
522  * empth_select
523  *
524  * Do a select on the given file.
525  * Wait for IO on it.
526  *
527  * This would be one of the main functions used within
528  * gen\io.c
529  */
530 void
531 empth_select(int fd, int flags)
532 {
533     loc_Thread_t *pThread =
534         (loc_Thread_t *)TlsGetValue(loc_GVAR.dwTLSIndex);
535     fd_set readmask;
536     fd_set writemask;
537     struct lwpProc *proc;
538     struct timeval tv;
539     int n;
540
541     loc_debug("%s select on %d",
542               flags == EMPTH_FD_READ ? "read" : "write", fd);
543     loc_BlockThisThread();
544
545     while (1) {
546         tv.tv_sec = 1000000;
547         tv.tv_usec = 0;
548
549         FD_ZERO(&readmask);
550         FD_ZERO(&writemask);
551
552         switch (flags) {
553         case EMPTH_FD_READ:
554             FD_SET(fd, &readmask);
555             break;
556         case EMPTH_FD_WRITE:
557             FD_SET(fd, &writemask);
558             break;
559         default:
560             logerror("bad flag %d passed to empth_select", flags);
561             empth_exit();
562         }
563
564         n = select(fd + 1, &readmask, &writemask, (fd_set *) 0, &tv);
565
566         if (n < 0) {
567             if (errno == EINTR) {
568                 /* go handle the signal */
569                 loc_debug("select broken by signal");
570                 goto done;
571                 return;
572             }
573             /* strange but we dont get EINTR on select broken by signal */
574             loc_debug("select failed (%s)", strerror(errno));
575             goto done;
576             return;
577         }
578
579         if (flags == EMPTH_FD_READ && FD_ISSET(fd, &readmask)) {
580             loc_debug("input ready");
581             break;
582         }
583         if (flags == EMPTH_FD_WRITE && FD_ISSET(fd, &writemask)) {
584             loc_debug("output ready");
585             break;
586         }
587     }
588
589   done:
590     loc_RunThisThread();
591 }
592
593 /************************
594  * empth_alarm
595  */
596 void
597 empth_alarm(int sig)
598 {
599     loc_Thread_t *pThread =
600         (loc_Thread_t *)TlsGetValue(loc_GVAR.dwTLSIndex);
601
602     loc_debug("got alarm signal  %d", sig);
603
604     /* Let it run if it is blocked like... */
605     SetEvent(pThread->hThreadEvent);
606 }
607
608 /************************
609  * empth_wakeup
610  *
611  * Wake up the specified thread.
612  */
613 void
614 empth_wakeup(empth_t *a)
615 {
616     loc_Thread_t *pThread = (loc_Thread_t *)a;
617
618     loc_debug("waking up thread %s", pThread->szName);
619
620     /* Let it run if it is blocked... */
621     SetEvent(pThread->hThreadEvent);
622 }
623
624 /************************
625  * empth_sleep
626  *
627  * Put the given thread to sleep...
628  */
629 void
630 empth_sleep(long until)
631 {
632     loc_Thread_t *pThread =
633         (loc_Thread_t *)TlsGetValue(loc_GVAR.dwTLSIndex);
634     unsigned long ulSec;
635
636     ulSec = until - time(0);
637
638     loc_debug("going to sleep %ld sec", ulSec);
639
640     loc_BlockThisThread();
641
642     WaitForSingleObject(pThread->hThreadEvent, (ulSec * 1000));
643
644     loc_debug("sleep done. Waiting to run.");
645
646     loc_RunThisThread();
647 }
648
649
650 /************************
651  * empth_sem_create
652  *
653  * Create a signalling semaphore.
654  */
655 empth_sem_t *
656 empth_sem_create(char *name, int cnt)
657 {
658     loc_Sem_t *pSem;
659
660     pSem = (loc_Sem_t *)malloc(sizeof(*pSem));
661     if (!pSem) {
662         logerror("out of memory at %s:%d", __FILE__, __LINE__);
663         return NULL;
664     }
665
666     memset(pSem, 0, sizeof(pSem));
667     strncpy(pSem->szName, name, sizeof(pSem->szName) - 1);
668
669     pSem->hMutex = CreateMutex(NULL, FALSE, NULL);
670     pSem->hEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
671     pSem->count = cnt;
672
673     return pSem;
674 }
675
676 /************************
677  * empth_sem_signal
678  *
679  * Hit/signal the specified semaphore.
680  */
681 void
682 empth_sem_signal(empth_sem_t *sm)
683 {
684     loc_Sem_t *pSem = (loc_Sem_t *)sm;
685
686     loc_debug("signal on semaphore %s:%d", pSem->szName, pSem->count);
687
688     /* Wait for the Semaphore */
689     WaitForSingleObject(pSem->hMutex, INFINITE);
690
691     if (pSem->count++ < 0) {
692         SetEvent(pSem->hEvent);
693     }
694
695     ReleaseMutex(pSem->hMutex);
696 }
697
698 /************************
699  * empth_sem_wait
700  *
701  * Wait for the specified signal semaphore
702  * to be signaled.
703  */
704 void
705 empth_sem_wait(empth_sem_t *sm)
706 {
707     loc_Thread_t *pThread =
708         (loc_Thread_t *)TlsGetValue(loc_GVAR.dwTLSIndex);
709     loc_Sem_t *pSem = (loc_Sem_t *)sm;
710
711     loc_debug("wait on semaphore %s:%d", pSem->szName, pSem->count);
712
713     /* Remove the thread from the running state. */
714     loc_BlockThisThread();
715
716     /* Wait for the Semaphore */
717     WaitForSingleObject(pSem->hMutex, INFINITE);
718     if (--pSem->count < 0) {
719         loc_debug("blocking");
720         ReleaseMutex(pSem->hMutex);
721
722         WaitForSingleObject(pSem->hEvent, INFINITE);
723
724         loc_debug("waking up");
725     } else
726         ReleaseMutex(pSem->hMutex);
727
728     loc_RunThisThread();
729 }
730
731 #endif /* _WIN32 */