]> git.pond.sub.org Git - empserver/blob - src/lib/empthread/pthread.c
Import of Empire 4.2.12
[empserver] / src / lib / empthread / pthread.c
1 /*
2  *  Empire - A multi-player, client/server Internet based war game.
3  *  Copyright (C) 1986-2000, 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  *  pthread.c: Interface from Empire threads to POSIX threads
29  * 
30  *  Known contributors to this file:
31  *     Sasha Mikheev
32  *     Steve McClure, 1998
33  */
34
35 #include <stdio.h>
36 #if !defined(_WIN32)
37 #include <sys/time.h>
38 #include <unistd.h>
39 #endif
40 #include <sys/types.h>
41 #include <signal.h>
42 #include <errno.h>
43 #include <string.h>
44
45 #include "misc.h"
46 #include "empthread.h"
47 #include "prototypes.h"
48
49 #include <stdarg.h>
50   
51 #ifdef _EMPTH_POSIX
52 static pthread_key_t ctx_key;
53 static int empth_flags;
54 static char **udata; /* pointer to out global context */
55
56 static pthread_mutex_t mtx_ctxsw;  /* thread in critical section */
57
58
59 #if 0
60 static void empth_setctx _PROTO((void *));
61 #endif
62 static void empth_restorectx _PROTO(());
63
64 void *
65 empth_start(void *ctx)
66 {
67     struct sigaction act;
68     extern emp_sig_t panic();
69     extern emp_sig_t shutdwn();
70
71     
72     /* actually it should inherit all this from main but... */ 
73 #ifdef SA_SIGINFO
74     act.sa_flags = SA_SIGINFO;
75 #endif
76     sigemptyset (&act.sa_mask);
77     act.sa_handler = shutdwn;
78         /* pthreads on Linux use SIGUSR1 (*shrug*) so only catch it if not on
79            a Linux box running POSIX threads -- STM */
80 #if !(defined(__linux__) && defined(_EMPTH_POSIX))
81     sigaction (SIGUSR1, &act, NULL);
82 #endif
83     sigaction (SIGTERM, &act, NULL);
84     sigaction (SIGINT, &act, NULL);
85     act.sa_handler = panic;
86     sigaction (SIGBUS, &act, NULL);
87     sigaction (SIGSEGV, &act, NULL);
88     sigaction (SIGILL, &act, NULL);
89     sigaction (SIGFPE, &act, NULL);
90     act.sa_handler = SIG_IGN;
91     sigaction(SIGPIPE, &act, NULL);
92
93     act.sa_handler = empth_alarm;
94     sigaction(SIGALRM, &act, NULL);
95
96     ((empth_t *)ctx)->id = pthread_self();
97     pthread_setspecific(ctx_key, ctx);
98     pthread_mutex_lock(&mtx_ctxsw);
99     *udata = ((empth_t *)ctx)->ud;
100     ((empth_t *)ctx)->ep(((empth_t *)ctx)->ud);
101     empth_exit();
102     return NULL;
103 }    
104     
105 static void
106 empth_status(char *format, ...)
107 {
108         va_list ap;
109         static  struct timeval startTime;
110         struct  timeval tv;
111         char    buf[1024];
112         int     sec, msec;
113         empth_t *a;
114         
115         va_start(ap, format);
116         if (empth_flags & EMPTH_PRINT) {
117                 if (startTime.tv_sec == 0)
118                         gettimeofday(&startTime, 0);
119                 gettimeofday(&tv, 0);
120                 sec = tv.tv_sec - startTime.tv_sec;
121                 msec = (tv.tv_usec - startTime.tv_usec) / 1000;
122                 if (msec < 0) {
123                         sec++;
124                         msec += 1000;
125                 }
126                 vsprintf(buf, format, ap);
127                 a = empth_self();
128                 printf("%d:%02d.%03d %17s: %s\n", sec/60, sec%60, msec/10,
129                        a->name,
130                        buf);
131
132         }
133         va_end(ap);
134 }
135
136
137 int
138 empth_init (char **ctx_ptr, int flags)
139 {
140     empth_t *ctx;
141     struct sigaction act;
142     
143
144     pthread_key_create(&ctx_key, 0);    
145 #ifdef _DECTHREADS_
146     pthread_mutex_init(&mtx_ctxsw, pthread_mutexattr_default);
147 #else
148     pthread_mutex_init(&mtx_ctxsw, 0);
149 #endif
150     
151     act.sa_flags = 0;
152     sigemptyset (&act.sa_mask);
153     act.sa_handler = empth_alarm;
154     sigaction(SIGALRM, &act, NULL);
155     
156     udata = ctx_ptr;
157     ctx = (empth_t *)malloc(sizeof(empth_t));
158     if(!ctx) {
159         logerror("pthread init failed: not enough memory");
160         exit(1);
161     }
162     ctx->name = "Main";
163     ctx->desc = "empire main";
164     ctx->ep = 0;
165     ctx->ud = 0;
166     ctx->id = pthread_self();
167     ctx->state = 0;     
168     pthread_setspecific(ctx_key, ctx);
169     pthread_mutex_lock(&mtx_ctxsw);    
170     empth_flags = flags;
171     logerror("pthreads initialized");
172     return 0;
173 }
174
175     
176 /*
177  * prio can be used for setting scheeduling policy but...
178  * it seems to be optional in POSIX threads and Solaris
179  * for example just ignores it.
180  * More then that priority is not needed even in lwp threads.
181  */
182 empth_t *
183 empth_create (int prio, void (*entry)(), int size, int flags,
184               char *name, char *desc, void *ud)
185 {
186     pthread_t t;
187     pthread_attr_t attr;
188     empth_t *ctx;
189     int eno;
190     
191     empth_status("creating new thread %s:%s", name, desc);
192     
193     ctx = (empth_t *)malloc(sizeof(empth_t));
194     if(!ctx) {
195         logerror("not enough memoty to create thread: %s (%s)", name, desc);
196         return NULL;
197     }
198     ctx->name = strdup(name);
199     ctx->desc = strdup(desc);
200     ctx->ud = ud;
201     ctx->state = 0;         
202     ctx->ep = entry;
203
204 #ifdef _DECTHREADS_
205     eno = pthread_attr_init(&attr) ? errno : 0;
206 #else
207     eno = pthread_attr_init(&attr);
208 #endif
209     if(eno) {
210         logerror("can not create thread attribute %s (%s): %s", name, desc,
211                  strerror(eno));
212         goto bad;
213     }
214
215 #if defined(__linux__)
216         /* Linux doesn't let you adjust the stack */
217 #elif defined(_DECTHREADS_)
218     /* DEC does not have PTHREAD_STACK_MIN constant */
219     /* Do not go below default size                 */
220     if(size > pthread_attr_getstacksize(attr))
221       pthread_attr_setstacksize(&attr, size);
222 #else
223     if(size < PTHREAD_STACK_MIN)
224       size = PTHREAD_STACK_MIN + 1;
225
226     pthread_attr_setstacksize(&attr, size);
227 #endif
228     
229     pthread_attr_setdetachstate (&attr, PTHREAD_CREATE_DETACHED);
230
231 #ifdef _DECTHREADS_
232     eno = pthread_create(&t, attr, empth_start, (void *)ctx) ? errno : 0;
233 #else
234     eno = pthread_create(&t, &attr, empth_start, (void *)ctx);
235 #endif
236     if (eno) {
237       logerror("can not create thread: %s (%s): %s", name, desc,
238                strerror(eno));
239       goto bad;
240     }
241     empth_status("new thread id is %d", t);
242     return ctx;
243     pthread_attr_destroy(&attr);
244 bad:
245     pthread_attr_destroy(&attr);
246     free(ctx);
247     return NULL;
248 }
249
250
251 #if 0
252 static void
253 empth_setctx(void *ct)
254 {
255     empth_t *ctx_ptr;
256
257 #ifdef _DECTHREADS_
258     pthread_getspecific(ctx_key, (pthread_addr_t *)&ctx_ptr);
259 #else
260     ctx_ptr = (empth_t *)pthread_getspecific(ctx_key);
261 #endif
262     ctx_ptr->ud = ct;
263     *udata = ((empth_t *)ctx_ptr)->ud;
264     pthread_setspecific(ctx_key, (void *)ctx_ptr);
265     empth_status("context saved");
266 }
267 #endif
268
269 static void 
270 empth_restorectx(void)
271 {
272     empth_t *ctx_ptr;
273     
274 #ifdef _DECTHREADS_
275     pthread_getspecific(ctx_key, (pthread_addr_t *)&ctx_ptr);
276 #else
277     ctx_ptr = (empth_t *)pthread_getspecific(ctx_key);
278 #endif
279     *udata = (char *)ctx_ptr->ud;
280     if (ctx_ptr->state == EMPTH_KILLED) {
281         empth_status("i am dead");
282         empth_exit();
283     }
284     empth_status("context restored");
285 }
286
287 empth_t *
288 empth_self(void)
289 {
290 #ifdef _DECTHREADS_
291   empth_t *ctx_ptr;
292   
293   pthread_getspecific(ctx_key, (pthread_addr_t *)&ctx_ptr);
294   return ctx_ptr;
295 #else
296   return (empth_t *)pthread_getspecific(ctx_key);
297 #endif
298 }
299
300 void
301 empth_exit (void)
302 {
303     empth_t *ctx_ptr;
304
305     pthread_mutex_unlock(&mtx_ctxsw);
306     empth_status("empth_exit");
307 #ifdef _DECTHREADS_
308     pthread_getspecific(ctx_key, (pthread_addr_t *)&ctx_ptr);
309 #else
310     ctx_ptr = (empth_t *)pthread_getspecific(ctx_key);
311 #endif
312         /* We want to leave the main thread around forever, until it's time
313            for it to die for real (in a shutdown) */
314     if (!strcmp(ctx_ptr->name, "Main")) {
315                 while(1) {
316 #ifdef _DECTHREADS_
317                         pthread_yield();
318 #endif
319                         sleep(60);
320                 }
321     }
322
323     free(ctx_ptr);
324     pthread_exit(0);
325 }
326         
327 void
328 empth_yield (void)
329 {
330     pthread_mutex_unlock(&mtx_ctxsw);
331     sleep(10); /* take a nap  pthread_yield(); */
332     pthread_mutex_lock(&mtx_ctxsw);
333     empth_restorectx();
334 }
335
336 void
337 empth_terminate(empth_t *a)
338 {
339     /* logerror("calling non supported function empth_terminate: %s:%d",
340              __FILE__, __LINE__); */
341     empth_status("killing thread %s", a->name);
342     a->state = EMPTH_KILLED;
343 #ifndef _DECTHREADS_
344     /* DEC and OSX do not have pthread_kill. Not sure that cancel is correct. */
345     #if (!defined __ppc__)
346         pthread_kill(a->id, SIGALRM);
347     #endif
348 #endif
349     return; 
350 }
351
352 void
353 empth_select(int fd, int flags)
354 {
355
356     fd_set readmask;
357     fd_set writemask;
358     struct timeval tv;
359     int n;
360     
361     pthread_mutex_unlock(&mtx_ctxsw);
362     empth_status("%s select on %d",
363                  flags == EMPTH_FD_READ ? "read" : "write", fd );
364     while (1) {
365         tv.tv_sec = 1000000;
366         tv.tv_usec = 0;
367
368         FD_ZERO(&readmask);
369         FD_ZERO(&writemask);
370         
371         switch(flags) {
372         case EMPTH_FD_READ:
373             FD_SET(fd, &readmask);
374             break;
375         case EMPTH_FD_WRITE:
376             FD_SET(fd, &writemask);
377             break;
378         default:
379             logerror("bad flag %d passed to empth_select", flags);
380             empth_exit();
381         }
382
383         n = select(fd + 1, &readmask, &writemask, (fd_set *)0, &tv);
384         
385         if (n < 0) {
386             if (errno == EINTR) {
387                 /* go handle the signal */
388                 empth_status("select broken by signal");
389                 goto done;
390                 return;
391             }
392             /* strange but we dont get EINTR on select broken by signal */
393             empth_status("select failed (%s)", strerror(errno));
394             goto done; 
395             return;
396         }
397         
398         if (flags == EMPTH_FD_READ && FD_ISSET(fd, &readmask)) {
399             empth_status("input ready");
400             break;
401         }
402         if (flags == EMPTH_FD_WRITE && FD_ISSET(fd, &writemask)) {
403             empth_status("output ready");
404             break;
405         }
406     }
407     
408 done:
409     pthread_mutex_lock(&mtx_ctxsw);
410     empth_restorectx();
411         
412 }
413
414
415 emp_sig_t
416 empth_alarm(int sig)
417 {
418     struct sigaction act;
419     empth_status("got alarm signal");
420 #ifdef SA_RESTART
421     act.sa_flags &= ~SA_RESTART;
422 #endif
423     sigemptyset (&act.sa_mask);
424     act.sa_handler = empth_alarm;
425     sigaction(SIGALRM, &act, NULL);
426 }
427
428 void
429 empth_wakeup(empth_t *a)
430 {
431     empth_status("waking up thread %s", a->name);
432 #ifndef _DECTHREADS_
433     #if (!defined __ppc__)
434         pthread_kill(a->id, SIGALRM);
435     #endif
436 #endif
437     empth_status("waiting for it to run");
438     /* empth_yield(); */
439 }
440
441 void
442 empth_sleep(long until)
443 {
444     struct timeval tv;
445
446     empth_status("going to sleep %ld sec", until - time(0));
447     pthread_mutex_unlock(&mtx_ctxsw);
448     tv.tv_sec = until - time(NULL);
449     tv.tv_usec = 0;
450     do {
451  select (0, NULL, NULL, NULL, &tv);
452     } while ((tv.tv_sec = until - time(NULL)) > 0);
453     empth_status("sleep done. Waiting for lock");
454     pthread_mutex_lock(&mtx_ctxsw);
455     empth_restorectx();
456 }
457
458
459 empth_sem_t *
460 empth_sem_create(char *name, int cnt)
461 {
462     empth_sem_t *sm;
463
464     sm = (empth_sem_t *)malloc(sizeof(empth_sem_t));
465     if(!sm) {
466         logerror("out of memory at %s:%d", __FILE__, __LINE__);
467         return NULL;
468     }
469     strncpy(sm->name, name, sizeof(sm->name)-1);
470     sm->count = cnt;
471 #ifdef _DECTHREADS_
472     pthread_mutex_init(&sm->mtx_update, pthread_mutexattr_default);
473     pthread_mutex_init(&sm->mtx_sem, pthread_mutexattr_default);
474     pthread_cond_init(&sm->cnd_sem, pthread_condattr_default);
475 #else
476     pthread_mutex_init(&sm->mtx_update, 0);
477     pthread_mutex_init(&sm->mtx_sem, 0);
478     pthread_cond_init(&sm->cnd_sem, 0);
479 #endif
480     return sm;
481 }
482
483 void
484 empth_sem_signal(empth_sem_t *sm)
485 {
486     empth_status("signal on semaphore %s:%d", sm->name, sm->count);
487     pthread_mutex_lock(&sm->mtx_update);
488     if(sm->count++ < 0) {
489         pthread_mutex_unlock(&sm->mtx_update);
490         pthread_mutex_lock(&sm->mtx_sem);
491         pthread_cond_signal(&sm->cnd_sem);
492         pthread_mutex_unlock(&sm->mtx_sem);
493     }
494     else
495         pthread_mutex_unlock(&sm->mtx_update);
496 }
497
498 void
499 empth_sem_wait (empth_sem_t *sm)
500 {
501     empth_status("wait on semaphore %s:%d", sm->name, sm->count);
502     pthread_mutex_lock(&sm->mtx_update);
503     if(--sm->count < 0) {
504         pthread_mutex_unlock(&sm->mtx_update);
505         empth_status("blocking");
506         pthread_mutex_unlock(&mtx_ctxsw);
507         pthread_mutex_lock(&sm->mtx_sem);
508         pthread_cond_wait(&sm->cnd_sem, &sm->mtx_sem);
509         empth_status("waking up");
510         pthread_mutex_unlock(&sm->mtx_sem);
511         pthread_mutex_lock(&mtx_ctxsw);
512         empth_restorectx();
513     }
514     else
515         pthread_mutex_unlock(&sm->mtx_update);
516 }
517
518 #endif