Port to x86-64 versions of Windows
[sbcl.git] / src / runtime / pthreads_win32.h
1 #ifndef WIN32_PTHREAD_INCLUDED
2 #define WIN32_PTHREAD_INCLUDED
3
4 #include <time.h>
5 #include <errno.h>
6 #include <sys/types.h>
7
8 #ifndef _SIGSET_T
9 typedef int sigset_t;
10 #endif
11
12
13 #define WIN32_LEAN_AND_MEAN
14 #include <windows.h>
15 #include <stdint.h>
16
17 /* 0 - Misc */
18
19 #define SIG_IGN ((void (*)(int, siginfo_t, void*))-1)
20 #define SIG_DFL ((void (*)(int, siginfo_t, void*))-2)
21
22 #define SIGHUP    1
23 #define SIGINT    2 /* Interactive attention */
24 #define SIGQUIT   3
25 #define SIGILL    4 /* Illegal instruction */
26 #define SIGPIPE   5
27 #define SIGALRM   6
28 #define SIGURG    7
29 #define SIGFPE    8 /* Floating point error */
30 #define SIGTSTP   9
31 #define SIGCHLD   10
32 #define SIGSEGV   11 /* Segmentation violation */
33 #define SIGIO     12
34 #define SIGXCPU   13
35 #define SIGXFSZ   14
36 #define SIGTERM   15 /* Termination request */
37 #define SIGVTALRM 16
38 #define SIGPROF   17
39 #define SIGWINCH  18
40 #define SIGBREAK  21 /* Control-break */
41 #define SIGABRT   22 /* Abnormal termination (abort) */
42
43 #define SIGRTMIN  23
44
45 #define NSIG 32     /* maximum signal number + 1 */
46
47 /* To avoid overusing system TLS, pthread provides its own */
48 #define PTHREAD_KEYS_MAX 128
49
50 #define PTHREAD_DESTRUCTOR_ITERATIONS 4
51
52 void pthreads_win32_init();
53
54 /* 1 - Thread */
55
56 typedef struct pthread_thread* pthread_t;
57
58 typedef struct pthread_attr_t {
59   unsigned int stack_size;
60 } pthread_attr_t;
61
62 int pthread_attr_init(pthread_attr_t *attr);
63 int pthread_attr_destroy(pthread_attr_t *attr);
64 int pthread_attr_setstack(pthread_attr_t *attr, void *stackaddr, size_t stacksize);
65 int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
66
67 typedef void (*pthread_cleanup_fn)(void* arg);
68
69 #define pthread_cleanup_push(fn, arg) { pthread_cleanup_fn __pthread_fn = fn; void *__pthread_arg = arg;
70 #define pthread_cleanup_pop(execute) if (execute) __pthread_fn(__pthread_arg); }
71
72 int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine) (void *), void *arg);
73 int pthread_equal(pthread_t thread1, pthread_t thread2);
74 int pthread_detach(pthread_t thread);
75 int pthread_join(pthread_t thread, void **retval);
76 int pthread_kill(pthread_t thread, int signum);
77
78 #ifndef PTHREAD_INTERNALS
79 pthread_t pthread_self(void) __attribute__((__const__));
80 #else
81 pthread_t pthread_self(void);
82 #endif
83
84 typedef DWORD pthread_key_t;
85 int pthread_key_create(pthread_key_t *key, void (*destructor)(void*));
86
87 #define SIG_BLOCK 1
88 #define SIG_UNBLOCK 2
89 #define SIG_SETMASK 3
90 #ifdef PTHREAD_INTERNALS
91 int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset);
92 #endif
93
94 /* 1a - Thread non-portable */
95
96 void pthread_np_suspend(pthread_t thread);
97 void pthread_np_suspend_with_signal(pthread_t thread, int signum);
98
99 /* Momentary suspend/getcontext/resume without locking or preventing
100    fiber reentrance.  This call is for asymmetric synchronization,
101    ensuring that the thread sees global state before doing any
102    globally visible stores.
103 */
104 void pthread_np_serialize(pthread_t thread);
105
106 void pthread_np_resume(pthread_t thread);
107 void pthread_np_request_interruption(pthread_t thread);
108 CONTEXT* pthread_np_publish_context(CONTEXT* maybe_save_old_one);
109 void pthread_np_unpublish_context();
110 void pthread_np_get_my_context_subset(CONTEXT* ctx);
111
112 /* 2 - Mutex */
113
114 typedef struct _pthread_mutex_info {
115   char padding[64];
116   CRITICAL_SECTION cs;
117   pthread_t owner;
118   const char* file;
119   int line;
120 } __attribute__((aligned(128))) *pthread_mutex_t;
121
122 typedef int pthread_mutexattr_t;
123 #define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t)-1)
124 int pthread_mutex_init(pthread_mutex_t * mutex, const pthread_mutexattr_t * attr);
125 int pthread_mutexattr_init(pthread_mutexattr_t*);
126 int pthread_mutexattr_destroy(pthread_mutexattr_t*);
127 int pthread_mutexattr_settype(pthread_mutexattr_t*, int);
128 #define PTHREAD_MUTEX_ERRORCHECK 0
129 int pthread_mutex_destroy(pthread_mutex_t *mutex);
130 int pthread_mutex_lock(pthread_mutex_t *mutex);
131 int pthread_mutex_trylock(pthread_mutex_t *mutex);
132 int pthread_mutex_lock_annotate_np(pthread_mutex_t *mutex, const char* file, int line);
133 int pthread_mutex_trylock_annotate_np(pthread_mutex_t *mutex, const char* file, int line);
134 int pthread_mutex_unlock(pthread_mutex_t *mutex);
135
136 /* 3 - Condition variable */
137
138 typedef struct thread_wakeup {
139   HANDLE event;
140   struct thread_wakeup *next;
141   volatile intptr_t *uaddr;
142   intptr_t uval;
143   int info;
144 } thread_wakeup;
145
146 typedef HANDLE (*cv_event_get_fn)();
147 typedef void (*cv_event_return_fn)(HANDLE event);
148
149 typedef struct pthread_cond_t {
150   pthread_mutex_t wakeup_lock;
151   struct thread_wakeup *first_wakeup;
152   struct thread_wakeup *last_wakeup;
153   unsigned char alertable;
154   cv_event_get_fn get_fn;
155   cv_event_return_fn return_fn;
156 } pthread_cond_t;
157
158 typedef struct pthread_condattr_t {
159   unsigned char alertable;
160   cv_event_get_fn get_fn;
161   cv_event_return_fn return_fn;
162 } pthread_condattr_t;
163
164 #ifndef _TIMESPEC_DEFINED
165 typedef struct timespec {
166   time_t tv_sec;
167   long tv_nsec;
168 } timespec;
169 #endif
170
171 // not implemented: PTHREAD_COND_INITIALIZER
172 int pthread_condattr_init(pthread_condattr_t *attr);
173 int pthread_condattr_destroy(pthread_condattr_t *attr);
174 int pthread_condattr_setevent_np(pthread_condattr_t *attr,
175                                  cv_event_get_fn get_fn, cv_event_return_fn ret_fn);
176 int pthread_cond_destroy(pthread_cond_t *cond);
177 int pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * attr);
178 int pthread_cond_broadcast(pthread_cond_t *cond);
179 int pthread_cond_signal(pthread_cond_t *cond);
180 int pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, const struct timespec * abstime);
181 int pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex);
182
183 /* some MinGWs seem to include it, others not: */
184 #ifndef ETIMEDOUT
185 # define ETIMEDOUT 123 //Something
186 #endif
187
188 int sched_yield();
189
190 void pthread_lock_structures();
191 void pthread_unlock_structures();
192
193 typedef void *(*pthread_fn)(void*);
194
195 typedef enum {
196   pthread_state_running,
197   pthread_state_finished,
198   pthread_state_joined
199 } pthread_thread_state;
200
201 typedef struct pthread_thread {
202   pthread_fn start_routine;
203   void* arg;
204   HANDLE handle;
205   pthread_cond_t *waiting_cond;
206   void *futex_wakeup;
207   sigset_t blocked_signal_set;
208   volatile sigset_t pending_signal_set;
209   void * retval;
210
211   pthread_mutex_t lock;
212   pthread_cond_t cond;
213   int detached;
214   pthread_thread_state state;
215
216   /* Boolean flag: thread will produce fibers instead of threads with
217      pthread_create */
218   int fiber_factory;
219
220   /* NULL if current thread has no fibers and is not a fiber; LPVOID
221      returned by CreateFiber or ConvertThreadToFiber otherwise */
222   void* fiber;
223
224   /* True if pthreads_win32 created fiber, false if it was already
225      present and just captured. We should delete our fiber when not
226      needed, but external fibers should be left intact. */
227   int own_fiber;
228
229   /* True if thread was created as fiber */
230   int created_as_fiber;
231
232   /* For noticed foreign threads, wait_handle contains a result of
233      RegisterWaitForSingleObject. */
234   HANDLE wait_handle;
235
236   /* FCAT group of a fiber. */
237   pthread_t fiber_group;
238
239   /* Mutex preventing double-entering a fiber */
240   pthread_mutex_t fiber_lock;
241
242   /* When fiber switches to another fiber (dying or not) it makes
243      another's fiber_prev point to it. If it's dead, the fiber entered
244      should clean up. */
245   pthread_t fiber_prev;
246
247   /* For non-running fiber, this field provides context of its
248      last-known running state: not for jumps et al., but for
249      conservative stack GCing.
250
251      With pthread_np_publish_context and pthread_np_unpublish_context
252      application may manage its thread context cooperatively, not
253      requiring real SuspendThread and ResumeThread for threads that
254      don't do anything interesting (as defined by application).
255
256      Esp field of fiber_context is used as a validity flag (must not
257      be NULL). */
258   CONTEXT fiber_context;
259
260   /* Thread TEB base (mostly informative/debugging) */
261   void* teb;
262
263   /* For fiber-callouts (call-in-fiber) support.  When switched into,
264      any fiber should execute fiber_callback and switch back to
265      fiber_prev. */
266   void (*fiber_callback)(void* context);
267   void *fiber_callback_context;
268
269   /* Pthread TLS, detached from windows system TLS */
270   void *specifics[PTHREAD_KEYS_MAX];
271 } pthread_thread;
272
273 #define PTHREAD_ONCE_INIT 0
274
275 typedef int pthread_once_t;
276 int pthread_once(pthread_once_t *once_control, void (*init_routine)(void));
277
278 static inline int pthread_setspecific(pthread_key_t key, const void *value)
279 {
280   pthread_self()->specifics[key] = (void*)value;
281   return 0;
282 }
283
284 typedef struct {
285   int bogus;
286 } siginfo_t;
287
288 #define SA_SIGINFO (1u<<1)
289 #define SA_NODEFER (1u<<2)
290 #define SA_RESTART (1u<<3)
291 #define SA_ONSTACK (1u<<4)
292
293 struct sigaction {
294   void (*sa_handler)(int);
295   void (*sa_sigaction)(int, siginfo_t*, void*);
296   sigset_t sa_mask;
297   int sa_flags;
298 };
299 int sigaction(int signum, const struct sigaction* act, struct sigaction* oldact);
300
301 int sigpending(sigset_t *set);
302
303 void pthread_np_add_pending_signal(pthread_t thread, int signum);
304 void pthread_np_remove_pending_signal(pthread_t thread, int signum);
305 sigset_t pthread_np_other_thread_sigpending(pthread_t thread);
306
307 int pthread_np_notice_thread();
308 int pthread_np_get_thread_context(pthread_t thread, CONTEXT* context);
309 int pthread_np_convert_self_to_fiber();
310 int pthread_np_switch_to_fiber(pthread_t fiber);
311 int pthread_np_run_in_fiber(pthread_t pth, void (*callback)(void*),
312                             void* context);
313 int pthread_np_set_fiber_factory_mode(int on);
314 int pthread_np_fiber_save_tls(int slot, int enable);
315 HANDLE pthread_np_get_handle(pthread_t pth);
316 void* pthread_np_get_lowlevel_fiber(pthread_t pth);
317 int pthread_np_delete_lowlevel_fiber(void* ll_fiber);
318 int pthread_np_ack_pending_signals(void* ucontext_arg);
319
320 /* Fiber context hooks */
321 extern void (*pthread_save_context_hook)();
322 extern void (*pthread_restore_context_hook)();
323
324 int sigemptyset(sigset_t *set);
325 int sigfillset(sigset_t *set);
326 int sigaddset(sigset_t *set, int signum);
327 int sigdelset(sigset_t *set, int signum);
328 int sigismember(const sigset_t *set, int signum);
329
330 typedef int sig_atomic_t;
331
332 /* Futexes */
333 int futex_wait(volatile intptr_t *lock_word, intptr_t oldval, long sec, unsigned long usec);
334 int futex_wake(volatile intptr_t *lock_word, int n);
335
336 /* Debugging */
337 void pthread_np_lose(int trace_depth, const char* fmt, ...);
338 struct _pthread_mutex_info DEAD_MUTEX;
339
340 static inline void pthread_np_assert_live_mutex(pthread_mutex_t* ptr,
341                                                 const char *action)
342 {
343     if (*ptr == &DEAD_MUTEX) {
344         pthread_np_lose(5,"Trying to %s dead mutex %p\n",action,ptr);
345     }
346 }
347
348 typedef HANDLE sem_t;
349
350 #define SEM_VALUE_MAX (int) (~0U >>1)
351
352 int sem_init(sem_t *sem, int pshared_not_implemented, unsigned int value);
353 int sem_post(sem_t *sem);
354 int sem_wait(sem_t *sem);
355 int sem_trywait(sem_t *sem);
356 int sem_destroy(sem_t *sem);
357
358 #ifndef PTHREAD_INTERNALS
359 static inline int pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset)
360 {
361   pthread_t self = pthread_self();
362   if (oldset)
363     *oldset = self->blocked_signal_set;
364   if (set) {
365     switch (how) {
366       case SIG_BLOCK:
367         self->blocked_signal_set |= *set;
368         break;
369       case SIG_UNBLOCK:
370         self->blocked_signal_set &= ~(*set);
371         break;
372       case SIG_SETMASK:
373         self->blocked_signal_set = *set;
374         break;
375     }
376   }
377   return 0;
378 }
379
380 /* Make speed-critical TLS access inline.
381
382    We don't check key range or validity here: (1) pthread spec is
383    explicit about undefined behavior for bogus keys, (2)
384    setspecific/getspecific should be as fast as possible.   */
385 #define pthread_getspecific pthread_getspecific_np_inline
386
387 static inline void *pthread_getspecific_np_inline(pthread_key_t key)
388 {
389   return pthread_self()->specifics[key];
390 }
391
392 #ifdef PTHREAD_DEBUG_OUTPUT
393 #define pthread_mutex_lock(mutex)               \
394   pthread_mutex_lock_annotate_np(mutex, __FILE__, __LINE__ )
395 #define pthread_mutex_trylock(mutex)            \
396   pthread_mutex_trylock_annotate_np(mutex, __FILE__ ,__LINE__)
397 #else
398
399 /* I'm not after inlinining _everything_, but those two things below are
400    (1) fast, (2) critical (3) short */
401 static inline int pthread_mutex_lock_np_inline(pthread_mutex_t *mutex)
402 {
403     pthread_np_assert_live_mutex(mutex,"lock");
404     if ((*mutex) == PTHREAD_MUTEX_INITIALIZER) {
405         return pthread_mutex_lock(mutex);
406     } else {
407         EnterCriticalSection(&(*mutex)->cs);
408         return 0;
409     }
410 }
411
412 static inline int pthread_mutex_unlock_np_inline(pthread_mutex_t *mutex)
413 {
414     pthread_np_assert_live_mutex(mutex,"unlock");
415     LeaveCriticalSection(&(*mutex)->cs);
416     return 0;
417 }
418
419 #define pthread_mutex_lock pthread_mutex_lock_np_inline
420 #define pthread_mutex_unlock pthread_mutex_unlock_np_inline
421
422 #endif  /* !PTHREAD_DEBUG_OUTPUT */
423 #endif  /* !PTHREAD_INTERNALS */
424 #endif  /* WIN32_PTHREAD_INCLUDED */