source: release/1.7/source/lisp-kernel/threads.h @ 15267

Last change on this file since 15267 was 14619, checked in by rme, 8 years ago

Merge shrink-tcr branch. This enables the 32-bit Windows lisp to run
on 64-bit Windows.

On 32-bit x86 ports, we expect to use a segment register to point to a
block of thread-local data called the TCR (thread context record).
This has always been kind of a bother on 32-bit Windows: we have been
using a kludge that allows us to use the %es segment register
(conditionalized on WIN32_ES_HACK).

Unfortunately, 64-bit Windows doesn't support using an LDT. This is
why the 32-bit lisp wouldn't run on 64-bit Windows.

The new scheme is to use some of the TlsSlots? (part of the Windows
TEB) for the most important parts of the TCR, and to introduce an "aux
vector" for the remaining TCR slots. Since %fs points to the TEB, we
can make this work. We reserve the last 34 (of 64) slots for our use,
and will die if we don't get them.

Microsoft's documentation says not to access the TlsSlots? directly
(you're supposed to use TlsGetValue/TlsSetValue?), so we're treading on
undocumented ground. Frankly, we've done worse.

This change introduces some ugliness. In lisp kernel C files, there's
a TCR_AUX(tcr) macro that expands to "tcr->aux" on win32, and to "tcr"
elsewhere.

If lisp or lap code has a pointer to a TCR, it's necessary to subtract
off target::tcr-bias (which on Windows/x86 is #xe10, the offset from
%fs to the TlsSlots? in the Windows TEB). We also sometimes have to load
target::tcr.aux to get at data which has been moved there.

These changes should only affect Windows/x86. The story on the other
platforms is just the same as before.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 6.4 KB
Line 
1/*
2   Copyright (C) 2009 Clozure Associates
3   Copyright (C) 1994-2001 Digitool, Inc
4   This file is part of Clozure CL. 
5
6   Clozure CL is licensed under the terms of the Lisp Lesser GNU Public
7   License , known as the LLGPL and distributed with Clozure CL as the
8   file "LICENSE".  The LLGPL consists of a preamble and the LGPL,
9   which is distributed with Clozure CL as the file "LGPL".  Where these
10   conflict, the preamble takes precedence. 
11
12   Clozure CL is referenced in the preamble as the "LIBRARY."
13
14   The LLGPL is also available online at
15   http://opensource.franz.com/preamble.html
16*/
17
18#include <stdlib.h>
19#ifndef WINDOWS
20#include <unistd.h>
21#include <sys/mman.h>
22#endif
23#undef __argv
24#include <stdio.h>
25#ifndef WINDOWS
26#include <pthread.h>
27#endif
28#ifdef WINDOWS
29#include <process.h>
30#endif
31#include <errno.h>
32#include <limits.h>
33
34#ifdef SOLARIS
35#include <sys/syscall.h>
36#include <sys/lwp.h>
37#endif
38
39#ifdef LINUX
40#include <sys/syscall.h>
41#endif
42
43#undef USE_MACH_SEMAPHORES
44#define USE_POSIX_SEMAPHORES
45#undef USE_WINDOWS_SEMAPHORES
46
47#ifdef DARWIN
48#define USE_MACH_SEMAPHORES 1
49#undef  USE_POSIX_SEMAPHORES
50#endif
51#ifdef WINDOWS
52#define USE_WINDOWS_SEMAPHORES 1
53#undef USE_POSIX_SEMAPHORES
54#ifdef WIN_32
55struct timespec {
56  int tv_sec;
57  int tv_nsec;
58};
59#endif
60#endif
61
62#ifdef USE_POSIX_SEMAPHORES
63#include <semaphore.h>
64#endif
65
66
67#ifdef USE_MACH_SEMAPHORES
68/* We have to use Mach semaphores, even if we're otherwise
69   using POSIX signals, etc. */
70#include <mach/task.h>
71#include <mach/semaphore.h>
72#endif
73
74#include <limits.h>
75
76#ifdef FREEBSD
77#include <pthread_np.h>
78#endif
79
80#ifndef WINDOWS
81#ifndef ANDROID
82#include <sched.h>
83#endif
84#endif
85
86#include "lisp.h"
87#include "lisp_globals.h"
88#include "gc.h"
89
90#ifdef USE_FUTEX
91#ifndef FUTEX_WAIT
92#define FUTEX_WAIT (0)
93#endif
94#ifndef FUTEX_WAKE
95#define FUTEX_WAKE (1)
96#endif
97#include <sys/syscall.h>
98#endif
99
100#ifndef WINDOWS
101#include <syslog.h>
102#endif
103
104Boolean extern threads_initialized;
105Boolean extern log_tcr_info;
106
107#define LOCK_SPINLOCK(x,tcr) get_spin_lock(&(x),tcr)
108#define RELEASE_SPINLOCK(x) (x)=0
109
110#ifdef WIN_32
111#define TCR_TO_TSD(tcr) ((void *)((natural)(tcr)))
112#define TCR_FROM_TSD(tsd) ((TCR *)((natural)(tsd)))
113#else
114#define TCR_TO_TSD(tcr) ((void *)((natural)(tcr)+TCR_BIAS))
115#define TCR_FROM_TSD(tsd) ((TCR *)((natural)(tsd)-TCR_BIAS))
116#endif
117
118#ifdef USE_WINDOWS_SEMAPHORES
119
120typedef void * SEMAPHORE;
121#define SEM_WAIT(s) WaitForSingleObject(s,INFINITE)
122#define SEM_RAISE(s) ReleaseSemaphore(s, 1L, NULL)
123#define SEM_BROADCAST(s, count) do {while(count) {SEM_RAISE(s);(count)--;}}while(0)
124#define SEM_TIMEDWAIT(s,t) WaitOnSingleObject(s,t)
125
126#endif
127#ifdef USE_POSIX_SEMAPHORES
128typedef sem_t * SEMAPHORE;
129#define SEM_WAIT(s) sem_wait((SEMAPHORE)s)
130#define SEM_RAISE(s) sem_post((SEMAPHORE)s)
131#define SEM_BROADCAST(s, count) do {while(count) {SEM_RAISE(s);(count)--;}}while(0)
132#define SEM_TIMEDWAIT(s,t) sem_timedwait((SEMAPHORE)s,(struct timespec *)t)
133#endif
134
135#ifdef USE_MACH_SEMAPHORES
136typedef semaphore_t SEMAPHORE;
137#define SEM_WAIT(s) semaphore_wait((SEMAPHORE)(natural)s)
138#define SEM_RAISE(s) semaphore_signal((SEMAPHORE)(natural)s)
139#define SEM_BROADCAST(s,count)semaphore_signal_all((SEMAPHORE)(natural)s)
140#define SEM_TIMEDWAIT(s,t) semaphore_timedwait((SEMAPHORE)(natural)s,t)
141#endif
142
143void signal_semaphore(SEMAPHORE s);
144int wait_on_semaphore(void *s, int seconds, int millis);
145void sem_wait_forever(SEMAPHORE s);
146
147#ifdef USE_POSIX_SEMAPHORES
148#define SEM_WAIT_FOREVER(s) sem_wait_forever((SEMAPHORE)s)
149#endif
150
151#ifdef USE_MACH_SEMAPHORES
152#define SEM_WAIT_FOREVER(s) sem_wait_forever((SEMAPHORE)(natural)s)
153#endif
154
155#ifdef USE_WINDOWS_SEMAPHORES
156#define SEM_WAIT_FOREVER(s) sem_wait_forever((SEMAPHORE)s)
157#endif
158
159typedef struct
160{
161  signed_natural avail;
162  TCR* owner;
163  signed_natural  count;
164  void* signal;
165  signed_natural waiting;
166  void *malloced_ptr;
167  signed_natural spinlock;
168} _recursive_lock, *RECURSIVE_LOCK;
169
170
171int lock_recursive_lock(RECURSIVE_LOCK, TCR *);
172int unlock_recursive_lock(RECURSIVE_LOCK, TCR *);
173RECURSIVE_LOCK new_recursive_lock(void);
174void destroy_recursive_lock(RECURSIVE_LOCK);
175int recursive_lock_trylock(RECURSIVE_LOCK, TCR *, int *);
176
177#define LOCK(m, t) lock_recursive_lock((RECURSIVE_LOCK)ptr_from_lispobj(m), (TCR *)t)
178#define UNLOCK(m, t) unlock_recursive_lock((RECURSIVE_LOCK)ptr_from_lispobj(m), (TCR *)t)
179
180/* Hmm.  This doesn't look like the MacOS Thread Manager ... */
181LispObj current_thread_osid(void);
182void *current_native_thread_id(void);
183void *new_semaphore(int);
184void destroy_semaphore(void**);
185void tsd_set(LispObj, void *);
186void *tsd_get(LispObj);
187TCR *new_tcr(natural, natural);
188void thread_init_tcr(TCR *tcr, void *stack_base, natural stack_size);
189TCR *initial_thread_tcr;
190
191#define DEFAULT_THREAD_STACK_SIZE ((size_t) -1)
192#define MINIMAL_THREAD_STACK_SIZE ((size_t) 0)
193
194
195Boolean create_system_thread(size_t stack_size, 
196                             void* stackaddr,
197#ifdef WINDOWS
198                             unsigned CALLBACK (*start_routine)(void *)
199#else
200                             void* (*start_routine)(void *)
201#endif
202                             ,
203                             void* param);
204
205TCR *get_tcr(Boolean);
206TCR *get_interrupt_tcr(Boolean);
207
208Boolean suspend_tcr(TCR *);
209Boolean resume_tcr(TCR *);
210Boolean kill_tcr(TCR *);
211
212int raise_thread_interrupt(TCR *target);
213
214Boolean lisp_suspend_tcr(TCR *);
215Boolean lisp_resume_tcr(TCR *);
216void lisp_suspend_other_threads(void);
217void lisp_resume_other_threads(void);
218
219typedef struct
220{
221  signed_natural spin; /* need spin lock to change fields */
222  signed_natural state; /* 0 = free, positive if writer, negative if readers; */
223  natural blocked_writers;
224  natural blocked_readers;
225  TCR  *writer;
226#ifdef USE_FUTEX
227  natural reader_signal;
228  natural writer_signal;
229#else
230  void * reader_signal;
231  void * writer_signal;
232#endif
233  void *malloced_ptr;
234} rwlock;
235
236
237rwlock * rwlock_new(void);
238void rwlock_destroy(rwlock *);
239int rwlock_rlock(rwlock *, TCR *, struct timespec *);
240int rwlock_wlock(rwlock *, TCR *, struct timespec *);
241int rwlock_try_wlock(rwlock *, TCR *);
242int rwlock_try_rlock(rwlock *, TCR *);
243int rwlock_unlock(rwlock *, TCR *);
244
245
246natural
247atomic_and(natural*, natural);
248
249natural
250atomic_ior(natural*, natural);
251
252#define SET_TCR_FLAG(t,bit) atomic_ior(&(t->flags),(1L<<bit))
253#define CLR_TCR_FLAG(t,bit) atomic_and(&(t->flags),~(1L<<bit))
254
255
256
257extern int thread_suspend_signal, thread_kill_signal;
258
259void *
260allocate_stack(natural);
261
262void
263suspend_resume_handler(int, siginfo_t *, ExceptionInformation *);
264
265/* Maybe later
266Boolean
267rwlock_try_rlock(rwlock *);
268
269Boolean
270rwlock_try_wlock(rwlock *);
271*/
Note: See TracBrowser for help on using the repository browser.