mirror of
git://git.code.sf.net/p/sbcl/sbcl
synced 2026-09-10 07:26:40 -04:00
win32: Garbage-collect pthreads_win32.[ch]
This commit is contained in:
parent
a603c8462e
commit
544548c21c
|
|
@ -8,90 +8,6 @@
|
|||
#include <time.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
#ifdef PTHREAD_DEBUG_OUTPUT
|
||||
#define pthshow(fmt,...) \
|
||||
do { \
|
||||
fprintf(stderr,fmt "\n", __VA_ARGS__); \
|
||||
fflush(stderr); \
|
||||
} while (0)
|
||||
|
||||
#define DEBUG_OWN(cs) do {(cs)->owner=pthread_self(); } while(0)
|
||||
#define DEBUG_RELEASE(cs) do {(cs)->owner=0;} while(0)
|
||||
|
||||
#else
|
||||
#define pthshow(fmt,...) do {} while (0)
|
||||
#define DEBUG_OWN(cs) do {} while(0)
|
||||
#define DEBUG_RELEASE(cs) do {} while(0)
|
||||
#endif
|
||||
|
||||
|
||||
struct freelist_cell {
|
||||
struct freelist_cell * next;
|
||||
void* data;
|
||||
};
|
||||
|
||||
struct freelist {
|
||||
void* (*create_fn)();
|
||||
CRITICAL_SECTION lock;
|
||||
struct freelist_cell * empty;
|
||||
struct freelist_cell * full;
|
||||
unsigned int count;
|
||||
};
|
||||
|
||||
#define mutex_lock(x) EnterCriticalSection(x)
|
||||
#define mutex_unlock(x) LeaveCriticalSection(x)
|
||||
|
||||
static void* freelist_get(struct freelist *fl)
|
||||
{
|
||||
void* result = NULL;
|
||||
if (fl->full) {
|
||||
mutex_lock(&fl->lock);
|
||||
if (fl->full) {
|
||||
struct freelist_cell *cell = fl->full;
|
||||
fl->full = cell->next;
|
||||
result = cell->data;
|
||||
cell->next = fl->empty;
|
||||
fl->empty = cell;
|
||||
}
|
||||
mutex_unlock(&fl->lock);
|
||||
}
|
||||
if (!result) {
|
||||
result = fl->create_fn();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static void freelist_return(struct freelist *fl, void*data)
|
||||
{
|
||||
struct freelist_cell* cell = NULL;
|
||||
if (fl->empty) {
|
||||
mutex_lock(&fl->lock);
|
||||
if (fl->empty) {
|
||||
cell = fl->empty;
|
||||
fl->empty = cell->next;
|
||||
goto add_locked;
|
||||
}
|
||||
mutex_unlock(&fl->lock);
|
||||
}
|
||||
if (!cell) {
|
||||
int i,n=32;
|
||||
cell = malloc(sizeof(*cell)*n);
|
||||
for (i=0; i<(n-1); ++i)
|
||||
cell[i].next = &cell[i+1];
|
||||
cell[i].next = NULL;
|
||||
}
|
||||
|
||||
mutex_lock(&fl->lock);
|
||||
++fl->count;
|
||||
add_locked:
|
||||
cell->data = data;
|
||||
cell->next = fl->full;
|
||||
fl->full = cell;
|
||||
mutex_unlock(&fl->lock);
|
||||
}
|
||||
|
||||
typedef unsigned char boolean;
|
||||
|
||||
/* TLS management internals */
|
||||
|
||||
DWORD thread_self_tls_index;
|
||||
|
|
@ -168,43 +84,6 @@ int _sbcl_pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static CRITICAL_SECTION mutex_init_lock;
|
||||
|
||||
int pthread_mutex_init(pthread_mutex_t * mutex, const pthread_mutexattr_t * attr)
|
||||
{
|
||||
*mutex = (struct _pthread_mutex_info*)malloc(sizeof(struct _pthread_mutex_info));
|
||||
InitializeCriticalSection(&(*mutex)->cs);
|
||||
(*mutex)->file = " (free) ";
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_mutexattr_init(pthread_mutexattr_t* attr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int pthread_mutexattr_destroy(pthread_mutexattr_t* attr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_mutexattr_settype(pthread_mutexattr_t* attr,int mutex_type)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct _pthread_mutex_info DEAD_MUTEX;
|
||||
|
||||
int pthread_mutex_destroy(pthread_mutex_t *mutex)
|
||||
{
|
||||
if (*mutex != PTHREAD_MUTEX_INITIALIZER) {
|
||||
pthread_np_assert_live_mutex(mutex,"destroy");
|
||||
DeleteCriticalSection(&(*mutex)->cs);
|
||||
free(*mutex);
|
||||
*mutex = &DEAD_MUTEX;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Add pending signal to (other) thread */
|
||||
void pthread_np_add_pending_signal(pthread_t thread, int signum)
|
||||
{
|
||||
|
|
@ -244,452 +123,6 @@ sigset_t pthread_np_other_thread_sigpending(pthread_t thread)
|
|||
0, 0);
|
||||
}
|
||||
|
||||
/* Mutex implementation uses CRITICAL_SECTIONs. Somethings to keep in
|
||||
mind: (1) uncontested locking is cheap; (2) long wait on a busy
|
||||
lock causes exception, so it should never be attempted; (3) those
|
||||
mutexes are recursive; (4) one thread locks, the other unlocks ->
|
||||
the next one hangs. */
|
||||
int pthread_mutex_lock(pthread_mutex_t *mutex)
|
||||
{
|
||||
pthread_np_assert_live_mutex(mutex,"lock");
|
||||
if (*mutex == PTHREAD_MUTEX_INITIALIZER) {
|
||||
mutex_lock(&mutex_init_lock);
|
||||
if (*mutex == PTHREAD_MUTEX_INITIALIZER) {
|
||||
pthread_mutex_init(mutex, NULL);
|
||||
}
|
||||
mutex_unlock(&mutex_init_lock);
|
||||
}
|
||||
EnterCriticalSection(&(*mutex)->cs);
|
||||
DEBUG_OWN(*mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_mutex_trylock(pthread_mutex_t *mutex)
|
||||
{
|
||||
pthread_np_assert_live_mutex(mutex,"trylock");
|
||||
if (*mutex == PTHREAD_MUTEX_INITIALIZER) {
|
||||
mutex_lock(&mutex_init_lock);
|
||||
if (*mutex == PTHREAD_MUTEX_INITIALIZER) {
|
||||
pthread_mutex_init(mutex, NULL);
|
||||
}
|
||||
mutex_unlock(&mutex_init_lock);
|
||||
}
|
||||
if (TryEnterCriticalSection(&(*mutex)->cs)) {
|
||||
DEBUG_OWN(*mutex);
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return EBUSY;
|
||||
}
|
||||
|
||||
/* Versions of lock/trylock useful for debugging. Our header file
|
||||
conditionally redefines lock/trylock to call them. */
|
||||
|
||||
int pthread_mutex_lock_annotate_np(pthread_mutex_t *mutex, const char* file, int line)
|
||||
{
|
||||
int contention = 0;
|
||||
pthread_np_assert_live_mutex(mutex,"lock");
|
||||
if (*mutex == PTHREAD_MUTEX_INITIALIZER) {
|
||||
mutex_lock(&mutex_init_lock);
|
||||
if (*mutex == PTHREAD_MUTEX_INITIALIZER) {
|
||||
pthread_mutex_init(mutex, NULL);
|
||||
pthshow("Mutex #x%p: automatic initialization; #x%p %s +%d",
|
||||
mutex, *mutex,
|
||||
file, line);
|
||||
}
|
||||
mutex_unlock(&mutex_init_lock);
|
||||
}
|
||||
if ((*mutex)->owner) {
|
||||
pthshow("Mutex #x%p -> #x%p: contention; owned by #x%p, wanted by #x%p",
|
||||
mutex, *mutex,
|
||||
(*mutex)->owner,
|
||||
pthread_self());
|
||||
pthshow("Mutex #x%p -> #x%p: contention notes: old %s +%d, new %s +%d",
|
||||
mutex, *mutex,
|
||||
(*mutex)->file,(*mutex)->line, file, line);
|
||||
contention = 1;
|
||||
}
|
||||
EnterCriticalSection(&(*mutex)->cs);
|
||||
if (contention) {
|
||||
pthshow("Mutex #x%p -> #x%p: contention end; left by #x%p, taken by #x%p",
|
||||
mutex, *mutex,
|
||||
(*mutex)->owner,
|
||||
pthread_self());
|
||||
pthshow("Mutex #x%p -> #x%p: contention notes: old %s +%d, new %s +%d",
|
||||
mutex, *mutex,
|
||||
(*mutex)->file,(*mutex)->line, file, line);
|
||||
}
|
||||
(*mutex)->owner = pthread_self();
|
||||
(*mutex)->file = file;
|
||||
(*mutex)->line = line;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_mutex_trylock_annotate_np(pthread_mutex_t *mutex, const char* file, int line)
|
||||
{
|
||||
int contention = 0;
|
||||
pthread_np_assert_live_mutex(mutex,"trylock");
|
||||
if (*mutex == PTHREAD_MUTEX_INITIALIZER) {
|
||||
mutex_lock(&mutex_init_lock);
|
||||
if (*mutex == PTHREAD_MUTEX_INITIALIZER) {
|
||||
pthread_mutex_init(mutex, NULL);
|
||||
}
|
||||
mutex_unlock(&mutex_init_lock);
|
||||
}
|
||||
if ((*mutex)->owner) {
|
||||
pthshow("Mutex #x%p -> #x%p: tried contention; owned by #x%p, wanted by #x%p",
|
||||
mutex, *mutex,
|
||||
(*mutex)->owner,
|
||||
pthread_self());
|
||||
pthshow("Mutex #x%p -> #x%p: contention notes: old %s +%d, new %s +%d",
|
||||
mutex, *mutex,
|
||||
(*mutex)->file,(*mutex)->line, file, line);
|
||||
contention = 1;
|
||||
}
|
||||
if (TryEnterCriticalSection(&(*mutex)->cs)) {
|
||||
if (contention) {
|
||||
pthshow("Mutex #x%p -> #x%p: contention end; left by #x%p, taken by #x%p",
|
||||
mutex, *mutex,
|
||||
(*mutex)->owner,
|
||||
pthread_self());
|
||||
pthshow("Mutex #x%p -> #x%p: contention notes: old %s +%d, new %s +%d",
|
||||
mutex, *mutex,
|
||||
(*mutex)->file,(*mutex)->line, file, line);
|
||||
}
|
||||
(*mutex)->owner = pthread_self();
|
||||
(*mutex)->file = file;
|
||||
(*mutex)->line = line;
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
return EBUSY;
|
||||
}
|
||||
|
||||
int pthread_mutex_unlock(pthread_mutex_t *mutex)
|
||||
{
|
||||
/* Owner is for debugging only; NB if mutex is used recursively,
|
||||
owner field will lie. */
|
||||
pthread_np_assert_live_mutex(mutex,"unlock");
|
||||
DEBUG_RELEASE(*mutex);
|
||||
LeaveCriticalSection(&(*mutex)->cs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Condition variables implemented with events and wakeup queues. */
|
||||
|
||||
/* .info field in wakeup record is an "opportunistic" indicator that
|
||||
wakeup has happened. On timeout from WaitForSingleObject, thread
|
||||
doesn't know (1) whether to reset event, (2) whether to (try) to
|
||||
find and unlink wakeup record. Let's let it know (of course,
|
||||
it will know for sure only under cv_wakeup_lock). */
|
||||
|
||||
#define WAKEUP_WAITING_NOTIMEOUT 0
|
||||
#define WAKEUP_WAITING_TIMEOUT 4
|
||||
|
||||
#define WAKEUP_HAPPENED 1
|
||||
#define WAKEUP_BY_INTERRUPT 2
|
||||
|
||||
static void* event_create()
|
||||
{
|
||||
return (void*)CreateEvent(NULL,FALSE,FALSE,NULL);
|
||||
}
|
||||
|
||||
static struct freelist event_freelist;
|
||||
|
||||
|
||||
unsigned int pthread_free_event_pool_size()
|
||||
{
|
||||
return event_freelist.count;
|
||||
}
|
||||
|
||||
static HANDLE fe_get_event()
|
||||
{
|
||||
return (HANDLE)freelist_get(&event_freelist);
|
||||
}
|
||||
|
||||
static void fe_return_event(HANDLE handle)
|
||||
{
|
||||
freelist_return(&event_freelist, (void*)handle);
|
||||
}
|
||||
|
||||
static HANDLE cv_default_event_get_fn()
|
||||
{
|
||||
pthread_thread *self = pthread_self();
|
||||
HANDLE event = self->cv_event;
|
||||
if (!event) {
|
||||
event = CreateEvent(NULL, FALSE, FALSE, NULL);
|
||||
self->cv_event = event;
|
||||
} else {
|
||||
/* ResetEvent(event); used to be here. Let's try without. It's
|
||||
safe in pthread_cond_wait: if WaitForSingleObjectEx ever
|
||||
returns, event is reset automatically, and the wakeup queue item
|
||||
is removed by the signaller under wakeup_lock.
|
||||
|
||||
pthread_cond_timedwait should reset the event if
|
||||
cv_wakeup_remove failed to find its wakeup record, otherwise
|
||||
it's safe too. */
|
||||
}
|
||||
return event;
|
||||
}
|
||||
|
||||
static void cv_default_event_return_fn(HANDLE event)
|
||||
{
|
||||
/* ResetEvent(event); could be here as well (and used to be).
|
||||
Avoiding syscalls makes sense, however. */
|
||||
}
|
||||
|
||||
static pthread_condattr_t cv_default_attr = {
|
||||
0, /* alertable */
|
||||
fe_get_event,
|
||||
fe_return_event,
|
||||
/* cv_default_event_get_fn, /\* get_fn *\/ */
|
||||
/* cv_default_event_return_fn /\* return_fn *\/ */
|
||||
};
|
||||
|
||||
int pthread_cond_init(pthread_cond_t * cv, const pthread_condattr_t * attr)
|
||||
{
|
||||
if (!attr)
|
||||
attr = &cv_default_attr;
|
||||
InitializeCriticalSection(&cv->wakeup_lock);
|
||||
cv->first_wakeup = NULL;
|
||||
cv->last_wakeup = NULL;
|
||||
cv->alertable = attr->alertable;
|
||||
cv->get_fn = attr->get_fn;
|
||||
cv->return_fn = attr->return_fn;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_condattr_init(pthread_condattr_t *attr)
|
||||
{
|
||||
*attr = cv_default_attr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_condattr_destroy(pthread_condattr_t *attr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
int pthread_condattr_setevent_np(pthread_condattr_t *attr,
|
||||
cv_event_get_fn get_fn, cv_event_return_fn ret_fn)
|
||||
{
|
||||
attr->get_fn = get_fn ? get_fn : fe_get_event;// cv_default_event_get_fn;
|
||||
attr->return_fn = ret_fn ? ret_fn : fe_return_event; // cv_default_event_return_fn;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_cond_destroy(pthread_cond_t *cv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_cond_broadcast(pthread_cond_t *cv)
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
HANDLE postponed[128];
|
||||
int npostponed = 0,i;
|
||||
|
||||
/* No strict requirements to memory visibility model, because of
|
||||
mutex unlock around waiting. */
|
||||
if (!cv->first_wakeup)
|
||||
return 0;
|
||||
mutex_lock(&cv->wakeup_lock);
|
||||
while (cv->first_wakeup)
|
||||
{
|
||||
struct thread_wakeup * w = cv->first_wakeup;
|
||||
HANDLE waitevent = w->event;
|
||||
cv->first_wakeup = w->next;
|
||||
w->info = WAKEUP_HAPPENED;
|
||||
postponed[npostponed++] = waitevent;
|
||||
if (/* w->info == WAKEUP_WAITING_TIMEOUT || */ npostponed ==
|
||||
sizeof(postponed)/sizeof(postponed[0])) {
|
||||
for (i=0; i<npostponed; ++i)
|
||||
SetEvent(postponed[i]);
|
||||
npostponed = 0;
|
||||
}
|
||||
++count;
|
||||
}
|
||||
cv->last_wakeup = NULL;
|
||||
mutex_unlock(&cv->wakeup_lock);
|
||||
for (i=0; i<npostponed; ++i)
|
||||
SetEvent(postponed[i]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_cond_signal(pthread_cond_t *cv)
|
||||
{
|
||||
struct thread_wakeup * w;
|
||||
/* No strict requirements to memory visibility model, because of
|
||||
mutex unlock around waiting. */
|
||||
if (!cv->first_wakeup)
|
||||
return 0;
|
||||
mutex_lock(&cv->wakeup_lock);
|
||||
w = cv->first_wakeup;
|
||||
if (w) {
|
||||
HANDLE waitevent = w->event;
|
||||
cv->first_wakeup = w->next;
|
||||
if (!cv->first_wakeup)
|
||||
cv->last_wakeup = NULL;
|
||||
w->info = WAKEUP_HAPPENED;
|
||||
SetEvent(waitevent);
|
||||
}
|
||||
mutex_unlock(&cv->wakeup_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return value is used for futexes: 0=ok, 1 on unexpected word change. */
|
||||
int cv_wakeup_add(struct pthread_cond_t* cv, struct thread_wakeup* w)
|
||||
{
|
||||
HANDLE event;
|
||||
w->next = NULL;
|
||||
mutex_lock(&cv->wakeup_lock);
|
||||
if (w->uaddr) {
|
||||
if (w->uval != *w->uaddr) {
|
||||
mutex_unlock(&cv->wakeup_lock);
|
||||
return 1;
|
||||
}
|
||||
pthread_self()->futex_wakeup = w;
|
||||
}
|
||||
event = cv->get_fn();
|
||||
w->event = event;
|
||||
if (cv->last_wakeup == w) {
|
||||
fprintf(stderr, "cv->last_wakeup == w\n");
|
||||
fflush(stderr);
|
||||
ExitProcess(0);
|
||||
}
|
||||
if (cv->last_wakeup != NULL)
|
||||
{
|
||||
cv->last_wakeup->next = w;
|
||||
cv->last_wakeup = w;
|
||||
}
|
||||
else
|
||||
{
|
||||
cv->first_wakeup = w;
|
||||
cv->last_wakeup = w;
|
||||
}
|
||||
mutex_unlock(&cv->wakeup_lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Return true if wakeup found, false if missing */
|
||||
int cv_wakeup_remove(struct pthread_cond_t* cv, struct thread_wakeup* w)
|
||||
{
|
||||
int result = 0;
|
||||
if (w->info == WAKEUP_HAPPENED || w->info == WAKEUP_BY_INTERRUPT)
|
||||
goto finish;
|
||||
mutex_lock(&cv->wakeup_lock);
|
||||
{
|
||||
if (w->info == WAKEUP_HAPPENED || w->info == WAKEUP_BY_INTERRUPT)
|
||||
goto unlock;
|
||||
if (cv->first_wakeup == w) {
|
||||
cv->first_wakeup = w->next;
|
||||
if (cv->last_wakeup == w)
|
||||
cv->last_wakeup = NULL;
|
||||
result = 1;
|
||||
} else {
|
||||
struct thread_wakeup * prev = cv->first_wakeup;
|
||||
while (prev && prev->next != w)
|
||||
prev = prev->next;
|
||||
if (!prev) {
|
||||
goto unlock;
|
||||
}
|
||||
prev->next = w->next;
|
||||
if (cv->last_wakeup == w)
|
||||
cv->last_wakeup = prev;
|
||||
result = 1;
|
||||
}
|
||||
}
|
||||
unlock:
|
||||
mutex_unlock(&cv->wakeup_lock);
|
||||
finish:
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int pthread_cond_wait(pthread_cond_t * cv, pthread_mutex_t * cs)
|
||||
{
|
||||
struct thread_wakeup w;
|
||||
w.uaddr = 0;
|
||||
w.info = WAKEUP_WAITING_NOTIMEOUT;
|
||||
cv_wakeup_add(cv, &w);
|
||||
if (cv->last_wakeup->next == cv->last_wakeup) {
|
||||
pthread_np_lose(5,"cv->last_wakeup->next == cv->last_wakeup\n");
|
||||
}
|
||||
if (cv->last_wakeup->next != NULL) {
|
||||
pthread_np_lose(5,"cv->last_wakeup->next == cv->last_wakeup\n");
|
||||
}
|
||||
pthread_self()->waiting_cond = cv;
|
||||
DEBUG_RELEASE(*cs);
|
||||
pthread_mutex_unlock(cs);
|
||||
do {
|
||||
if (cv->alertable) {
|
||||
while (WaitForSingleObjectEx(w.event, INFINITE, TRUE) == WAIT_IO_COMPLETION);
|
||||
} else {
|
||||
WaitForSingleObject(w.event, INFINITE);
|
||||
}
|
||||
} while (w.info == WAKEUP_WAITING_NOTIMEOUT);
|
||||
pthread_self()->waiting_cond = NULL;
|
||||
/* Event is signalled once, wakeup is dequeued by signaller. */
|
||||
cv->return_fn(w.event);
|
||||
pthread_mutex_lock(cs);
|
||||
DEBUG_OWN(*cs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int pthread_cond_timedwait(pthread_cond_t * cv, pthread_mutex_t * cs,
|
||||
const struct timespec * abstime)
|
||||
{
|
||||
DWORD rv;
|
||||
struct thread_wakeup w;
|
||||
pthread_t self = pthread_self();
|
||||
|
||||
w.info = WAKEUP_WAITING_TIMEOUT;
|
||||
w.uaddr = 0;
|
||||
cv_wakeup_add(cv, &w);
|
||||
if (cv->last_wakeup->next == cv->last_wakeup) {
|
||||
fprintf(stderr, "cv->last_wakeup->next == cv->last_wakeup\n");
|
||||
ExitProcess(0);
|
||||
}
|
||||
self->waiting_cond = cv;
|
||||
DEBUG_RELEASE(*cs);
|
||||
/* barrier (release); waiting_cond globally visible */
|
||||
pthread_mutex_unlock(cs);
|
||||
{
|
||||
struct timeval cur_tm;
|
||||
long sec, msec;
|
||||
gettimeofday(&cur_tm, NULL);
|
||||
sec = abstime->tv_sec - cur_tm.tv_sec;
|
||||
msec = sec * 1000 + abstime->tv_nsec / 1000000 - cur_tm.tv_usec / 1000;
|
||||
if (msec < 0)
|
||||
msec = 0;
|
||||
do {
|
||||
if (cv->alertable) {
|
||||
while ((rv = WaitForSingleObjectEx(w.event, msec, TRUE))
|
||||
== WAIT_IO_COMPLETION);
|
||||
} else {
|
||||
rv = WaitForSingleObject(w.event, msec);
|
||||
}
|
||||
} while (rv == WAIT_OBJECT_0 && w.info == WAKEUP_WAITING_TIMEOUT);
|
||||
}
|
||||
self->waiting_cond = NULL;
|
||||
|
||||
if (rv == WAIT_TIMEOUT) {
|
||||
if (!cv_wakeup_remove(cv, &w)) {
|
||||
/* Someone removed our wakeup record: though we got a timeout,
|
||||
event was (will be) signalled before we are here.
|
||||
Consume this wakeup. */
|
||||
WaitForSingleObject(w.event, INFINITE);
|
||||
}
|
||||
}
|
||||
cv->return_fn(w.event);
|
||||
pthread_mutex_lock(cs);
|
||||
DEBUG_OWN(*cs);
|
||||
if (rv == WAIT_TIMEOUT)
|
||||
return ETIMEDOUT;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
int sched_yield()
|
||||
{
|
||||
/* http://stackoverflow.com/questions/1383943/switchtothread-vs-sleep1
|
||||
|
|
@ -703,7 +136,6 @@ int sched_yield()
|
|||
void pthreads_win32_init()
|
||||
{
|
||||
thread_self_tls_index = TlsAlloc();
|
||||
InitializeCriticalSection(&mutex_init_lock);
|
||||
pthread_np_notice_thread();
|
||||
}
|
||||
|
||||
|
|
@ -712,7 +144,6 @@ VOID CALLBACK pthreads_win32_unnotice(void* parameter, BOOLEAN timerOrWait)
|
|||
{
|
||||
pthread_t pth = parameter;
|
||||
|
||||
if (pth->cv_event) CloseHandle(pth->cv_event);
|
||||
CloseHandle(pth->handle);
|
||||
|
||||
UnregisterWait(pth->wait_handle);
|
||||
|
|
@ -780,77 +211,4 @@ int sigpending(sigset_t *set)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void pthread_np_lose(int trace_depth, const char* fmt, ...)
|
||||
{
|
||||
va_list header;
|
||||
void* frame;
|
||||
int n = 0;
|
||||
void** lastseh;
|
||||
|
||||
va_start(header,fmt);
|
||||
vfprintf(stderr,fmt,header);
|
||||
for (lastseh = *(void**)NtCurrentTeb();
|
||||
lastseh && (lastseh!=(void*)0xFFFFFFFF);
|
||||
lastseh = *lastseh);
|
||||
|
||||
fprintf(stderr, "Backtrace: %s (pthread %p)\n", header, pthread_self());
|
||||
for (frame = __builtin_frame_address(0); frame; frame=*(void**)frame)
|
||||
{
|
||||
if ((n++)>trace_depth)
|
||||
return;
|
||||
fprintf(stderr, "[#%02d]: ebp = %p, ret = %p\n",n,
|
||||
frame, ((void**)frame)[1]);
|
||||
}
|
||||
ExitProcess(0);
|
||||
}
|
||||
|
||||
int
|
||||
sem_init(sem_t *sem, int pshared_not_implemented, unsigned int value)
|
||||
{
|
||||
sem_t semh = CreateSemaphore(NULL, value, SEM_VALUE_MAX, NULL);
|
||||
if (!semh)
|
||||
return -1;
|
||||
*sem = semh;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
sem_post(sem_t *sem)
|
||||
{
|
||||
return !ReleaseSemaphore(*sem, 1, NULL);
|
||||
}
|
||||
|
||||
static int
|
||||
sem_wait_timeout(sem_t *sem, DWORD ms)
|
||||
{
|
||||
switch (WaitForSingleObject(*sem, ms)) {
|
||||
case WAIT_OBJECT_0:
|
||||
return 0;
|
||||
case WAIT_TIMEOUT:
|
||||
/* errno = EAGAIN; */
|
||||
return -1;
|
||||
default:
|
||||
/* errno = EINVAL; */
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
sem_wait(sem_t *sem)
|
||||
{
|
||||
return sem_wait_timeout(sem, INFINITE);
|
||||
}
|
||||
|
||||
int
|
||||
sem_trywait(sem_t *sem)
|
||||
{
|
||||
return sem_wait_timeout(sem, 0);
|
||||
}
|
||||
|
||||
int
|
||||
sem_destroy(sem_t *sem)
|
||||
{
|
||||
return !CloseHandle(*sem);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -50,23 +50,12 @@ typedef int sigset_t;
|
|||
#define NSIG 32 /* maximum signal number + 1 */
|
||||
#endif
|
||||
|
||||
/* To avoid overusing system TLS, pthread provides its own */
|
||||
#define PTHREAD_KEYS_MAX 128
|
||||
|
||||
#define PTHREAD_DESTRUCTOR_ITERATIONS 4
|
||||
|
||||
#define PTHREAD_STACK_MIN 0
|
||||
|
||||
void pthreads_win32_init();
|
||||
|
||||
/* 1 - Thread */
|
||||
|
||||
typedef struct pthread_thread* pthread_t;
|
||||
|
||||
typedef int pthread_attr_t; /* arbitrary */
|
||||
|
||||
typedef void (*pthread_cleanup_fn)(void* arg);
|
||||
|
||||
int pthread_equal(pthread_t thread1, pthread_t thread2);
|
||||
int pthread_kill(pthread_t thread, int signum);
|
||||
|
||||
|
|
@ -85,58 +74,6 @@ extern DWORD thread_self_tls_index;
|
|||
int _sbcl_pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset);
|
||||
#endif
|
||||
|
||||
/* 2 - Mutex */
|
||||
|
||||
typedef struct _pthread_mutex_info {
|
||||
char padding[64];
|
||||
CRITICAL_SECTION cs;
|
||||
pthread_t owner;
|
||||
const char* file;
|
||||
int line;
|
||||
} __attribute__((aligned(128))) *pthread_mutex_t;
|
||||
|
||||
typedef int pthread_mutexattr_t;
|
||||
#define PTHREAD_MUTEX_INITIALIZER ((pthread_mutex_t)-1)
|
||||
int pthread_mutex_init(pthread_mutex_t * mutex, const pthread_mutexattr_t * attr);
|
||||
int pthread_mutexattr_init(pthread_mutexattr_t*);
|
||||
int pthread_mutexattr_destroy(pthread_mutexattr_t*);
|
||||
int pthread_mutexattr_settype(pthread_mutexattr_t*, int);
|
||||
#define PTHREAD_MUTEX_ERRORCHECK 0
|
||||
int pthread_mutex_destroy(pthread_mutex_t *mutex);
|
||||
int pthread_mutex_lock(pthread_mutex_t *mutex);
|
||||
int pthread_mutex_trylock(pthread_mutex_t *mutex);
|
||||
int pthread_mutex_lock_annotate_np(pthread_mutex_t *mutex, const char* file, int line);
|
||||
int pthread_mutex_trylock_annotate_np(pthread_mutex_t *mutex, const char* file, int line);
|
||||
int pthread_mutex_unlock(pthread_mutex_t *mutex);
|
||||
|
||||
/* 3 - Condition variable */
|
||||
|
||||
typedef struct thread_wakeup {
|
||||
HANDLE event;
|
||||
struct thread_wakeup *next;
|
||||
volatile intptr_t *uaddr;
|
||||
intptr_t uval;
|
||||
int info;
|
||||
} thread_wakeup;
|
||||
|
||||
typedef HANDLE (*cv_event_get_fn)();
|
||||
typedef void (*cv_event_return_fn)(HANDLE event);
|
||||
|
||||
typedef struct pthread_cond_t {
|
||||
CRITICAL_SECTION wakeup_lock;
|
||||
struct thread_wakeup *first_wakeup;
|
||||
struct thread_wakeup *last_wakeup;
|
||||
unsigned char alertable;
|
||||
cv_event_get_fn get_fn;
|
||||
cv_event_return_fn return_fn;
|
||||
} pthread_cond_t;
|
||||
|
||||
typedef struct pthread_condattr_t {
|
||||
unsigned char alertable;
|
||||
cv_event_get_fn get_fn;
|
||||
cv_event_return_fn return_fn;
|
||||
} pthread_condattr_t;
|
||||
|
||||
#ifndef _TIMESPEC_DEFINED
|
||||
typedef struct timespec {
|
||||
time_t tv_sec;
|
||||
|
|
@ -144,18 +81,6 @@ typedef struct timespec {
|
|||
} timespec;
|
||||
#endif
|
||||
|
||||
// not implemented: PTHREAD_COND_INITIALIZER
|
||||
int pthread_condattr_init(pthread_condattr_t *attr);
|
||||
int pthread_condattr_destroy(pthread_condattr_t *attr);
|
||||
int pthread_condattr_setevent_np(pthread_condattr_t *attr,
|
||||
cv_event_get_fn get_fn, cv_event_return_fn ret_fn);
|
||||
int pthread_cond_destroy(pthread_cond_t *cond);
|
||||
int pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * attr);
|
||||
int pthread_cond_broadcast(pthread_cond_t *cond);
|
||||
int pthread_cond_signal(pthread_cond_t *cond);
|
||||
int pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, const struct timespec * abstime);
|
||||
int pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex);
|
||||
|
||||
/* some MinGWs seem to include it, others not: */
|
||||
#ifndef ETIMEDOUT
|
||||
# define ETIMEDOUT 123 //Something
|
||||
|
|
@ -163,16 +88,9 @@ int pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex);
|
|||
|
||||
int sched_yield();
|
||||
|
||||
void pthread_lock_structures();
|
||||
void pthread_unlock_structures();
|
||||
|
||||
typedef void *(*pthread_fn)(void*);
|
||||
|
||||
typedef struct pthread_thread {
|
||||
HANDLE handle;
|
||||
struct thread *vm_thread;
|
||||
pthread_cond_t *waiting_cond;
|
||||
void *futex_wakeup;
|
||||
sigset_t blocked_signal_set;
|
||||
volatile sigset_t pending_signal_set;
|
||||
|
||||
|
|
@ -182,8 +100,6 @@ typedef struct pthread_thread {
|
|||
|
||||
/* Thread TEB base (mostly informative/debugging) */
|
||||
void* teb;
|
||||
|
||||
HANDLE cv_event;
|
||||
} pthread_thread;
|
||||
|
||||
typedef struct {
|
||||
|
|
@ -219,28 +135,6 @@ int sigismember(const sigset_t *set, int signum);
|
|||
|
||||
typedef int sig_atomic_t;
|
||||
|
||||
/* Debugging */
|
||||
void pthread_np_lose(int trace_depth, const char* fmt, ...);
|
||||
extern struct _pthread_mutex_info DEAD_MUTEX;
|
||||
|
||||
static inline void pthread_np_assert_live_mutex(pthread_mutex_t* ptr,
|
||||
const char *action)
|
||||
{
|
||||
if (*ptr == &DEAD_MUTEX) {
|
||||
pthread_np_lose(5,"Trying to %s dead mutex %p\n",action,ptr);
|
||||
}
|
||||
}
|
||||
|
||||
typedef HANDLE sem_t;
|
||||
|
||||
#define SEM_VALUE_MAX (int) (~0U >>1)
|
||||
|
||||
int sem_init(sem_t *sem, int pshared_not_implemented, unsigned int value);
|
||||
int sem_post(sem_t *sem);
|
||||
int sem_wait(sem_t *sem);
|
||||
int sem_trywait(sem_t *sem);
|
||||
int sem_destroy(sem_t *sem);
|
||||
|
||||
#ifndef PTHREAD_INTERNALS
|
||||
static inline int _sbcl_pthread_sigmask(int how, const sigset_t *set, sigset_t *oldset)
|
||||
{
|
||||
|
|
@ -263,36 +157,5 @@ static inline int _sbcl_pthread_sigmask(int how, const sigset_t *set, sigset_t *
|
|||
return 0;
|
||||
}
|
||||
|
||||
#ifdef PTHREAD_DEBUG_OUTPUT
|
||||
#define pthread_mutex_lock(mutex) \
|
||||
pthread_mutex_lock_annotate_np(mutex, __FILE__, __LINE__ )
|
||||
#define pthread_mutex_trylock(mutex) \
|
||||
pthread_mutex_trylock_annotate_np(mutex, __FILE__ ,__LINE__)
|
||||
#else
|
||||
|
||||
/* I'm not after inlinining _everything_, but those two things below are
|
||||
(1) fast, (2) critical (3) short */
|
||||
static inline int pthread_mutex_lock_np_inline(pthread_mutex_t *mutex)
|
||||
{
|
||||
pthread_np_assert_live_mutex(mutex,"lock");
|
||||
if ((*mutex) == PTHREAD_MUTEX_INITIALIZER) {
|
||||
return pthread_mutex_lock(mutex);
|
||||
} else {
|
||||
EnterCriticalSection(&(*mutex)->cs);
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
static inline int pthread_mutex_unlock_np_inline(pthread_mutex_t *mutex)
|
||||
{
|
||||
pthread_np_assert_live_mutex(mutex,"unlock");
|
||||
LeaveCriticalSection(&(*mutex)->cs);
|
||||
return 0;
|
||||
}
|
||||
|
||||
#define pthread_mutex_lock pthread_mutex_lock_np_inline
|
||||
#define pthread_mutex_unlock pthread_mutex_unlock_np_inline
|
||||
|
||||
#endif /* !PTHREAD_DEBUG_OUTPUT */
|
||||
#endif /* !PTHREAD_INTERNALS */
|
||||
#endif /* WIN32_PTHREAD_INCLUDED */
|
||||
|
|
|
|||
|
|
@ -456,7 +456,6 @@ unregister_thread(struct thread *th,
|
|||
set_thread_self(self); \
|
||||
struct thread* th = self->vm_thread
|
||||
#define THREAD_TRAMPOLINE_EPILOGUE \
|
||||
if (self->cv_event) CloseHandle(self->cv_event); \
|
||||
free_thread_struct(th); \
|
||||
HANDLE h = self->handle; \
|
||||
free(self); \
|
||||
|
|
|
|||
|
|
@ -30,9 +30,6 @@
|
|||
|
||||
#ifdef LISP_FEATURE_SB_THREAD
|
||||
#include "pthreads_win32.h"
|
||||
/* prevent inclusion of a mingw semaphore.h */
|
||||
#define CANNOT_USE_POSIX_SEM_T
|
||||
typedef sem_t os_sem_t;
|
||||
#else
|
||||
typedef void *siginfo_t;
|
||||
typedef int sigset_t;
|
||||
|
|
|
|||
Loading…
Reference in a new issue