2000-02-17 20:38:33 +01:00
|
|
|
/* thread.cc: Locking and threading module functions
|
|
|
|
|
|
|
|
Copyright 1998, 2000 Cygnus Solutions.
|
|
|
|
|
|
|
|
Written by Marco Fuykschot <marco@ddi.nl>
|
|
|
|
|
|
|
|
This file is part of Cygwin.
|
|
|
|
|
|
|
|
This software is a copyrighted work licensed under the terms of the
|
|
|
|
Cygwin license. Please consult the file "CYGWIN_LICENSE" for
|
|
|
|
details. */
|
|
|
|
|
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
# include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#ifdef _MT_SAFE
|
|
|
|
#include <errno.h>
|
|
|
|
#include "winsup.h"
|
|
|
|
#include <assert.h>
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <syslog.h>
|
|
|
|
|
|
|
|
extern int threadsafe;
|
|
|
|
|
|
|
|
#define MT_INTERFACE user_data->threadinterface
|
|
|
|
|
|
|
|
#define NOT_IMP(n) system_printf("not implemented %s\n",n); return 0;
|
|
|
|
|
|
|
|
#define CHECKHANDLE(rval,release) \
|
|
|
|
if ( ! item->HandleOke() ) { \
|
|
|
|
if ( release ) item->used=false; \
|
|
|
|
return rval; };
|
|
|
|
|
|
|
|
#define GETTHREAD(n) \
|
|
|
|
if ( ! thread ) system_printf("thread is NULL");\
|
|
|
|
SetResourceLock(LOCK_THREAD_LIST,READ_LOCK,n);\
|
|
|
|
ThreadItem *item=user_data->threadinterface->GetThread(thread); \
|
|
|
|
ReleaseResourceLock(LOCK_THREAD_LIST,READ_LOCK,n); \
|
|
|
|
if ( ! item ) return EINVAL; \
|
|
|
|
CHECKHANDLE(EINVAL,0);
|
|
|
|
|
|
|
|
#define GETMUTEX(n) \
|
|
|
|
SetResourceLock(LOCK_MUTEX_LIST,READ_LOCK,n); \
|
|
|
|
MutexItem* item=user_data->threadinterface->GetMutex(mutex); \
|
|
|
|
ReleaseResourceLock(LOCK_MUTEX_LIST,READ_LOCK,n); \
|
|
|
|
if ( ! item ) return EINVAL; \
|
|
|
|
CHECKHANDLE(EINVAL,0);
|
|
|
|
|
|
|
|
#define GETSEMA(n) \
|
|
|
|
SetResourceLock(LOCK_SEM_LIST,READ_LOCK,n); \
|
|
|
|
SemaphoreItem* item=user_data->threadinterface->GetSemaphore(sem); \
|
|
|
|
ReleaseResourceLock(LOCK_SEM_LIST,READ_LOCK,n); \
|
|
|
|
if ( ! item ) return EINVAL; \
|
|
|
|
CHECKHANDLE(EINVAL,0);
|
|
|
|
|
|
|
|
#define CHECKITEM(rn,rm,fn) \
|
|
|
|
if ( ! item ) { \
|
|
|
|
ReleaseResourceLock(rn,rm,fn); \
|
|
|
|
return EINVAL; }; \
|
|
|
|
|
|
|
|
struct _reent *
|
|
|
|
_reent_clib ()
|
|
|
|
{
|
|
|
|
int tmp = GetLastError ();
|
|
|
|
struct __reent_t *_r = (struct __reent_t *) TlsGetValue (MT_INTERFACE->reent_index);
|
|
|
|
|
|
|
|
#ifdef _CYG_THREAD_FAILSAFE
|
|
|
|
if (_r == 0)
|
|
|
|
{
|
|
|
|
system_printf ("local thread storage not inited");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
SetLastError (tmp);
|
|
|
|
return _r->_clib;
|
|
|
|
};
|
|
|
|
|
|
|
|
struct _winsup_t *
|
|
|
|
_reent_winsup ()
|
|
|
|
{
|
|
|
|
int tmp = GetLastError ();
|
|
|
|
struct __reent_t *_r;
|
|
|
|
_r = (struct __reent_t *) TlsGetValue (MT_INTERFACE->reent_index);
|
|
|
|
#ifdef _CYG_THREAD_FAILSAFE
|
|
|
|
if (_r == 0)
|
|
|
|
{
|
|
|
|
system_printf ("local thread storage not inited");
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
SetLastError (tmp);
|
|
|
|
return _r->_winsup;
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
SetResourceLock (int _res_id, int _mode, const char *_function)
|
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
if (!threadsafe)
|
|
|
|
return;
|
|
|
|
#endif
|
|
|
|
thread_printf ("Set resource lock %d mode %d for %s start", _res_id, _mode, _function);
|
|
|
|
EnterCriticalSection (user_data->resourcelocks->Lock (_res_id));
|
|
|
|
|
|
|
|
#ifdef _CYG_THREAD_FAILSAFE
|
|
|
|
user_data->resourcelocks->owner = GetCurrentThreadId ();
|
|
|
|
user_data->resourcelocks->count++;
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ReleaseResourceLock (int _res_id, int _mode, const char *_function)
|
|
|
|
{
|
|
|
|
#if 0
|
|
|
|
if (!threadsafe)
|
|
|
|
return;
|
|
|
|
#endif
|
|
|
|
thread_printf ("Release resource lock %d mode %d for %s done", _res_id, _mode, _function);
|
|
|
|
|
|
|
|
#ifdef _CYG_THREAD_FAILSAFE
|
|
|
|
AssertResourceOwner (_res_id, _mode);
|
|
|
|
user_data->resourcelocks->count--;
|
|
|
|
if (user_data->resourcelocks->count == 0)
|
|
|
|
user_data->resourcelocks->owner = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
LeaveCriticalSection (user_data->resourcelocks->Lock (_res_id));
|
|
|
|
};
|
|
|
|
|
|
|
|
#ifdef _CYG_THREAD_FAILSAFE
|
|
|
|
void
|
|
|
|
AssertResourceOwner (int _res_id, int _mode)
|
|
|
|
{
|
|
|
|
|
|
|
|
thread_printf ("Assert Resource lock %d ==> for %p , real : %d , threadid %d count %d owner %d", _res_id, user_data, (myself ? myself->pid : -1), GetCurrentThreadId (), user_data->resourcelocks->count, user_data->resourcelocks->owner);
|
|
|
|
if (user_data && (user_data->resourcelocks->owner != GetCurrentThreadId ()))
|
|
|
|
{
|
|
|
|
system_printf ("assertion failed, not the resource owner");
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
LPCRITICAL_SECTION
|
|
|
|
ResourceLocks::Lock (int _resid)
|
|
|
|
{
|
|
|
|
if (!inited)
|
|
|
|
{
|
|
|
|
system_printf ("lock called before initialization");
|
|
|
|
};
|
|
|
|
|
|
|
|
thread_printf ("Get Resource lock %d ==> %p for %p , real : %d , threadid %d ", _resid, &lock, user_data, (myself ? myself->pid : -1), GetCurrentThreadId ());
|
|
|
|
return &lock;
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
ResourceLocks::Init ()
|
|
|
|
{
|
|
|
|
thread_printf ("Init resource lock %p -> %p", this, &lock);
|
|
|
|
|
|
|
|
InitializeCriticalSection (&lock);
|
|
|
|
inited = true;
|
|
|
|
|
|
|
|
#ifdef _CYG_THREAD_FAILSAFE
|
|
|
|
owner = 0;
|
|
|
|
count = 0;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
thread_printf ("Resource lock %p inited by %p , %d", &lock, user_data, (myself ? myself->pid : -1));
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
ResourceLocks::Delete ()
|
|
|
|
{
|
|
|
|
if (inited)
|
|
|
|
{
|
|
|
|
thread_printf ("Close Resource Locks %p ", &lock);
|
|
|
|
DeleteCriticalSection (&lock);
|
|
|
|
inited = false;
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// Thread interface
|
|
|
|
|
|
|
|
void
|
|
|
|
MTinterface::ReleaseItem (MTitem * _item)
|
|
|
|
{
|
|
|
|
_item->used = false;
|
|
|
|
};
|
|
|
|
|
|
|
|
MTitem *
|
|
|
|
MTinterface::Find (void *_value, int (*comp) (void *, void *), register int &_index, MTList * _list)
|
|
|
|
{
|
|
|
|
register MTitem *current = NULL;
|
|
|
|
for (; _index < _list->index; _index++)
|
|
|
|
{
|
|
|
|
current = _list->items[_index];
|
|
|
|
if (current->used && comp (current, _value))
|
|
|
|
break;
|
|
|
|
current = NULL;
|
|
|
|
};
|
|
|
|
return current;
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
MTinterface::Find (MTitem & _item, MTList * _list)
|
|
|
|
{
|
|
|
|
register MTitem *current;
|
|
|
|
register int _index = 0;
|
|
|
|
for (; _index < _list->index; _index++)
|
|
|
|
{
|
|
|
|
current = _list->items[_index];
|
|
|
|
if (current->used && current == &_item)
|
|
|
|
break;
|
|
|
|
};
|
|
|
|
return (_index == _list->index ? -1 : _index);
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
MTinterface::FindNextUnused (MTList * _list)
|
|
|
|
{
|
|
|
|
register int i = 0;
|
|
|
|
for (; i < _list->index && _list->items[i] != NULL && _list->items[i]->used && _list->items[i]->joinable != 'Y'; i++);
|
|
|
|
return i;
|
|
|
|
};
|
|
|
|
|
|
|
|
MTitem *
|
|
|
|
MTinterface::GetItem (int _index, MTList * _list)
|
|
|
|
{
|
|
|
|
return (_index < _list->index ? _list->items[_index] : NULL);
|
|
|
|
};
|
|
|
|
|
|
|
|
MTitem *
|
|
|
|
MTinterface::SetItem (int _index, MTitem * _item, MTList * _list)
|
|
|
|
{
|
|
|
|
if (_index == _list->index && _list->index < MT_MAX_ITEMS)
|
|
|
|
_list->index++;
|
|
|
|
return (_index < _list->index ? _list->items[_index] = _item : NULL);
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
CmpPthreadObj (void *_i, void *_value)
|
|
|
|
{
|
|
|
|
return ((MTitem *) _i)->Id () == *(int *) _value;
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
CmpThreadId (void *_i, void *_id)
|
|
|
|
{
|
|
|
|
return ((ThreadItem *) _i)->thread_id == *(DWORD *) _id;
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
MTinterface::Init0 ()
|
|
|
|
{
|
|
|
|
for (int i = 0; i < MT_MAX_ITEMS; i++)
|
|
|
|
{
|
|
|
|
threadlist.items[i] = NULL;
|
|
|
|
mutexlist.items[i] = NULL;
|
|
|
|
semalist.items[i] = NULL;
|
|
|
|
};
|
|
|
|
|
|
|
|
threadlist.index = 0;
|
|
|
|
mutexlist.index = 0;
|
|
|
|
semalist.index = 0;
|
|
|
|
|
|
|
|
reent_index = TlsAlloc ();
|
|
|
|
|
|
|
|
reents._clib = _impure_ptr;
|
|
|
|
reents._winsup = &winsup_reent;
|
|
|
|
|
|
|
|
winsup_reent._process_logmask = LOG_UPTO (LOG_DEBUG);
|
|
|
|
winsup_reent._grp_pos = 0;
|
|
|
|
winsup_reent._process_ident = 0;
|
|
|
|
winsup_reent._process_logopt = 0;
|
|
|
|
winsup_reent._process_facility = 0;
|
|
|
|
|
|
|
|
TlsSetValue (reent_index, &reents);
|
|
|
|
// the static reent_data will be used in the main thread
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
MTinterface::Init1 ()
|
|
|
|
{
|
|
|
|
// create entry for main thread
|
|
|
|
|
|
|
|
int i = FindNextUnused (&threadlist);
|
|
|
|
assert (i == 0);
|
|
|
|
ThreadItem *item = (ThreadItem *) GetItem (i, &threadlist);
|
|
|
|
|
|
|
|
item = (ThreadItem *) SetItem (i, &mainthread, &threadlist);
|
|
|
|
item->used = true;
|
|
|
|
item->win32_obj_id = myself->hProcess;
|
|
|
|
item->thread_id = GetCurrentThreadId ();
|
|
|
|
item->function = NULL;
|
|
|
|
|
|
|
|
item->sigs = NULL;
|
|
|
|
item->sigmask = NULL;
|
|
|
|
item->sigtodo = NULL;
|
|
|
|
};
|
|
|
|
|
|
|
|
void
|
|
|
|
MTinterface::ClearReent ()
|
|
|
|
{
|
|
|
|
struct _reent *r = _REENT;
|
|
|
|
memset (r, 0, sizeof (struct _reent));
|
|
|
|
|
|
|
|
r->_errno = 0;
|
|
|
|
r->_stdin = &r->__sf[0];
|
|
|
|
r->_stdout = &r->__sf[1];
|
|
|
|
r->_stderr = &r->__sf[2];
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
ThreadItem *
|
|
|
|
MTinterface::CreateThread (pthread_t * t, TFD (func), void *arg, pthread_attr_t a)
|
|
|
|
{
|
|
|
|
AssertResourceOwner (LOCK_THREAD_LIST, WRITE_LOCK | READ_LOCK);
|
|
|
|
|
|
|
|
int i = FindNextUnused (&threadlist);
|
|
|
|
|
|
|
|
ThreadItem *item = (ThreadItem *) GetItem (i, &threadlist);
|
|
|
|
if (!item)
|
|
|
|
item = (ThreadItem *) SetItem (i, new ThreadItem (), &threadlist);
|
|
|
|
if (!item)
|
|
|
|
system_printf ("thread creation failed");
|
|
|
|
|
|
|
|
item->used = true;
|
|
|
|
item->function = func;
|
|
|
|
item->arg = arg;
|
|
|
|
item->attr = a;
|
|
|
|
|
|
|
|
item->win32_obj_id = ::CreateThread (&sec_none_nih, item->attr.stacksize,
|
|
|
|
(LPTHREAD_START_ROUTINE) thread_init_wrapper, item, 0, &item->thread_id);
|
|
|
|
|
|
|
|
CHECKHANDLE (NULL, 1);
|
|
|
|
|
|
|
|
*t = (pthread_t) item->win32_obj_id;
|
|
|
|
|
|
|
|
return item;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
MutexItem *
|
|
|
|
MTinterface::CreateMutex (pthread_mutex_t * mutex)
|
|
|
|
{
|
|
|
|
AssertResourceOwner (LOCK_MUTEX_LIST, WRITE_LOCK | READ_LOCK);
|
|
|
|
|
|
|
|
int i = FindNextUnused (&mutexlist);
|
|
|
|
|
|
|
|
MutexItem *item = (MutexItem *) GetItem (i, &mutexlist);
|
|
|
|
if (!item)
|
|
|
|
item = (MutexItem *) SetItem (i, new MutexItem (), &mutexlist);
|
|
|
|
if (!item)
|
|
|
|
system_printf ("mutex creation failed");
|
|
|
|
item->used = true;
|
|
|
|
|
|
|
|
item->win32_obj_id = ::CreateMutex (&sec_none_nih, false, NULL);
|
|
|
|
|
|
|
|
CHECKHANDLE (NULL, 1);
|
|
|
|
|
|
|
|
*mutex = (pthread_mutex_t) item->win32_obj_id;
|
|
|
|
|
|
|
|
return item;
|
|
|
|
}
|
|
|
|
|
|
|
|
ThreadItem *
|
|
|
|
MTinterface::GetCallingThread ()
|
|
|
|
{
|
|
|
|
AssertResourceOwner (LOCK_THREAD_LIST, READ_LOCK);
|
|
|
|
DWORD id = GetCurrentThreadId ();
|
|
|
|
int index = 0;
|
|
|
|
return (ThreadItem *) Find (&id, &CmpThreadId, index, &threadlist);
|
|
|
|
};
|
|
|
|
|
|
|
|
ThreadItem *
|
|
|
|
MTinterface::GetThread (pthread_t * _t)
|
|
|
|
{
|
|
|
|
AssertResourceOwner (LOCK_THREAD_LIST, READ_LOCK);
|
|
|
|
int index = 0;
|
|
|
|
return (ThreadItem *) Find (_t, &CmpPthreadObj, index, &threadlist);
|
|
|
|
};
|
|
|
|
|
|
|
|
MutexItem *
|
|
|
|
MTinterface::GetMutex (pthread_mutex_t * mp)
|
|
|
|
{
|
|
|
|
AssertResourceOwner (LOCK_MUTEX_LIST, READ_LOCK);
|
|
|
|
int index = 0;
|
|
|
|
return (MutexItem *) Find (mp, &CmpPthreadObj, index, &mutexlist);
|
|
|
|
}
|
|
|
|
|
|
|
|
SemaphoreItem *
|
|
|
|
MTinterface::GetSemaphore (sem_t * sp)
|
|
|
|
{
|
|
|
|
AssertResourceOwner (LOCK_SEM_LIST, READ_LOCK);
|
|
|
|
int index = 0;
|
|
|
|
return (SemaphoreItem *) Find (sp, &CmpPthreadObj, index, &semalist);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
MTitem::Destroy ()
|
|
|
|
{
|
|
|
|
CloseHandle (win32_obj_id);
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
MutexItem::Lock ()
|
|
|
|
{
|
|
|
|
return WaitForSingleObject (win32_obj_id, INFINITE);
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
MutexItem::TryLock ()
|
|
|
|
{
|
|
|
|
return WaitForSingleObject (win32_obj_id, 0);
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
MutexItem::UnLock ()
|
|
|
|
{
|
|
|
|
return ReleaseMutex (win32_obj_id);
|
|
|
|
}
|
|
|
|
|
|
|
|
SemaphoreItem *
|
|
|
|
MTinterface::CreateSemaphore (sem_t * _s, int pshared, int _v)
|
|
|
|
{
|
|
|
|
AssertResourceOwner (LOCK_SEM_LIST, WRITE_LOCK | READ_LOCK);
|
|
|
|
|
|
|
|
int i = FindNextUnused (&semalist);
|
|
|
|
|
|
|
|
SemaphoreItem *item = (SemaphoreItem *) GetItem (i, &semalist);
|
|
|
|
if (!item)
|
|
|
|
item = (SemaphoreItem *) SetItem (i, new SemaphoreItem (), &semalist);
|
|
|
|
if (!item)
|
|
|
|
system_printf ("semaphore creation failed");
|
|
|
|
item->used = true;
|
|
|
|
item->shared = pshared;
|
|
|
|
|
|
|
|
item->win32_obj_id = ::CreateSemaphore (&sec_none_nih, _v, _v, NULL);
|
|
|
|
|
|
|
|
CHECKHANDLE (NULL, 1);
|
|
|
|
|
|
|
|
*_s = (sem_t) item->win32_obj_id;
|
|
|
|
|
|
|
|
return item;
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
SemaphoreItem::Wait ()
|
|
|
|
{
|
|
|
|
return WaitForSingleObject (win32_obj_id, INFINITE);
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
SemaphoreItem::Post ()
|
|
|
|
{
|
|
|
|
long pc;
|
|
|
|
return ReleaseSemaphore (win32_obj_id, 1, &pc);
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
SemaphoreItem::TryWait ()
|
|
|
|
{
|
|
|
|
return WaitForSingleObject (win32_obj_id, 0);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
////////////////////////// Pthreads
|
|
|
|
|
|
|
|
void *
|
|
|
|
thread_init_wrapper (void *_arg)
|
|
|
|
{
|
|
|
|
// Setup the local/global storage of this thread
|
|
|
|
|
|
|
|
ThreadItem *thread = (ThreadItem *) _arg;
|
|
|
|
struct __reent_t local_reent;
|
|
|
|
struct _winsup_t local_winsup;
|
|
|
|
struct _reent local_clib;
|
|
|
|
|
|
|
|
struct sigaction _sigs[NSIG];
|
|
|
|
sigset_t _sig_mask; /* one set for everything to ignore. */
|
|
|
|
LONG _sigtodo[NSIG + __SIGOFFSET];
|
|
|
|
|
|
|
|
// setup signal structures
|
|
|
|
thread->sigs = _sigs;
|
|
|
|
thread->sigmask = &_sig_mask;
|
|
|
|
thread->sigtodo = _sigtodo;
|
|
|
|
|
|
|
|
memset (&local_clib, 0, sizeof (struct _reent));
|
|
|
|
memset (&local_winsup, 0, sizeof (struct _winsup_t));
|
|
|
|
|
|
|
|
local_clib._errno = 0;
|
|
|
|
local_clib._stdin = &local_clib.__sf[0];
|
|
|
|
local_clib._stdout = &local_clib.__sf[1];
|
|
|
|
local_clib._stderr = &local_clib.__sf[2];
|
|
|
|
|
|
|
|
local_reent._clib = &local_clib;
|
|
|
|
local_reent._winsup = &local_winsup;
|
|
|
|
|
|
|
|
local_winsup._process_logmask = LOG_UPTO (LOG_DEBUG);
|
|
|
|
|
|
|
|
|
|
|
|
if (!TlsSetValue (MT_INTERFACE->reent_index, &local_reent))
|
|
|
|
system_printf ("local storage for thread couldn't be set");
|
|
|
|
|
|
|
|
#ifdef _CYG_THREAD_FAILSAFE
|
|
|
|
if (_REENT == _impure_ptr)
|
|
|
|
system_printf ("local storage for thread isn't setup correctly");
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
thread_printf ("started thread %p %p %p %p %p %p", _arg, &local_clib, _impure_ptr, thread, thread->function, thread->arg);
|
|
|
|
|
|
|
|
|
|
|
|
// call the user's thread
|
|
|
|
void *ret = thread->function (thread->arg);
|
|
|
|
|
|
|
|
// FIX ME : cleanup code
|
|
|
|
|
|
|
|
// thread->used = false; // release thread entry
|
|
|
|
thread->return_ptr = ret;
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
__pthread_create (pthread_t * thread, const pthread_attr_t * attr, TFD (start_routine), void *arg)
|
|
|
|
{
|
|
|
|
SetResourceLock (LOCK_THREAD_LIST, WRITE_LOCK | READ_LOCK, "__pthread_create");
|
|
|
|
|
|
|
|
pthread_attr_t a;
|
|
|
|
ThreadItem *item;
|
|
|
|
|
|
|
|
if (attr)
|
|
|
|
item = MT_INTERFACE->CreateThread (thread, start_routine, arg, *attr);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
__pthread_attr_init (&a);
|
|
|
|
item = MT_INTERFACE->CreateThread (thread, start_routine, arg, a);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
CHECKITEM (LOCK_THREAD_LIST, WRITE_LOCK | READ_LOCK, "__pthread_create")
|
|
|
|
|
|
|
|
ReleaseResourceLock (LOCK_THREAD_LIST, WRITE_LOCK | READ_LOCK, "__pthread_create");
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
__pthread_attr_init (pthread_attr_t * attr)
|
|
|
|
{
|
|
|
|
attr->stacksize = 0;
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
__pthread_attr_setstacksize (pthread_attr_t * attr, size_t size)
|
|
|
|
{
|
|
|
|
attr->stacksize = size;
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
__pthread_attr_getstacksize (pthread_attr_t * attr, size_t * size)
|
|
|
|
{
|
|
|
|
*size = attr->stacksize;
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
2000-02-24 04:53:22 +01:00
|
|
|
__pthread_attr_destroy (pthread_attr_t * /*attr*/)
|
2000-02-17 20:38:33 +01:00
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
__pthread_exit (void *value_ptr)
|
|
|
|
{
|
|
|
|
ThreadItem *item = MT_INTERFACE->GetCallingThread();
|
|
|
|
item->return_ptr = value_ptr;
|
|
|
|
ExitThread(0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
__pthread_join(pthread_t * thread, void **return_val)
|
|
|
|
{
|
|
|
|
ThreadItem *item=user_data->threadinterface->GetThread(thread);
|
|
|
|
|
|
|
|
|
|
|
|
if (!item)
|
|
|
|
return ESRCH;
|
|
|
|
|
|
|
|
if (item->joinable == 'N')
|
|
|
|
{
|
|
|
|
if (return_val)
|
|
|
|
*return_val = NULL;
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
item->joinable = 'N';
|
|
|
|
WaitForSingleObject((HANDLE)*thread, INFINITE);
|
|
|
|
if (return_val)
|
|
|
|
*return_val = item->return_ptr;
|
|
|
|
}/* End if*/
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
__pthread_detach(pthread_t * thread)
|
|
|
|
{
|
|
|
|
ThreadItem *item=user_data->threadinterface->GetThread(thread);
|
|
|
|
if (!item)
|
|
|
|
return ESRCH;
|
|
|
|
|
|
|
|
if (item->joinable == 'N')
|
|
|
|
{
|
|
|
|
item->return_ptr = NULL;
|
|
|
|
return EINVAL;
|
|
|
|
}
|
|
|
|
|
|
|
|
item->joinable = 'N';
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
__pthread_suspend(pthread_t * thread)
|
|
|
|
{
|
|
|
|
ThreadItem *item=user_data->threadinterface->GetThread(thread);
|
|
|
|
if (!item)
|
|
|
|
return ESRCH;
|
|
|
|
|
|
|
|
if (item->suspended == false)
|
|
|
|
{
|
|
|
|
item->suspended = true;
|
|
|
|
SuspendThread( (HANDLE)*thread);
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
__pthread_continue(pthread_t * thread)
|
|
|
|
{
|
|
|
|
ThreadItem *item=user_data->threadinterface->GetThread(thread);
|
|
|
|
if (!item)
|
|
|
|
return ESRCH;
|
|
|
|
|
|
|
|
if (item->suspended == true)
|
|
|
|
ResumeThread( (HANDLE)*thread);
|
|
|
|
item->suspended = false;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
unsigned long
|
|
|
|
__pthread_getsequence_np (pthread_t * thread)
|
|
|
|
{
|
|
|
|
GETTHREAD ("__pthread_getsequence_np");
|
|
|
|
return item->GetThreadId ();
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Thread SpecificData */
|
|
|
|
int
|
2000-02-24 04:53:22 +01:00
|
|
|
__pthread_key_create (pthread_key_t */*key*/)
|
2000-02-17 20:38:33 +01:00
|
|
|
{
|
|
|
|
NOT_IMP ("_p_key_create\n");
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
2000-02-24 04:53:22 +01:00
|
|
|
__pthread_key_delete (pthread_key_t */*key*/)
|
2000-02-17 20:38:33 +01:00
|
|
|
{
|
|
|
|
NOT_IMP ("_p_key_delete\n");
|
|
|
|
};
|
|
|
|
int
|
2000-02-24 04:53:22 +01:00
|
|
|
__pthread_setspecific (pthread_key_t */*key*/, const void */*value*/)
|
2000-02-17 20:38:33 +01:00
|
|
|
{
|
|
|
|
NOT_IMP ("_p_key_setsp\n");
|
|
|
|
};
|
|
|
|
void *
|
2000-02-24 04:53:22 +01:00
|
|
|
__pthread_getspecific (pthread_key_t */*key*/)
|
2000-02-17 20:38:33 +01:00
|
|
|
{
|
|
|
|
NOT_IMP ("_p_key_getsp\n");
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Thread signal */
|
|
|
|
int
|
|
|
|
__pthread_kill (pthread_t * thread, int sig)
|
|
|
|
{
|
|
|
|
// lock myself, for the use of thread2signal
|
|
|
|
// two differ kills might clash: FIX ME
|
|
|
|
GETTHREAD ("__pthread_kill");
|
|
|
|
|
|
|
|
if (item->sigs)
|
|
|
|
myself->setthread2signal (item);
|
|
|
|
|
2000-05-17 07:49:51 +02:00
|
|
|
int rval = _kill (myself->pid, sig);
|
2000-02-17 20:38:33 +01:00
|
|
|
|
|
|
|
// unlock myself
|
|
|
|
return rval;
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
__pthread_sigmask (int operation, const sigset_t * set, sigset_t * old_set)
|
|
|
|
{
|
|
|
|
SetResourceLock (LOCK_THREAD_LIST, READ_LOCK, "__pthread_sigmask");
|
|
|
|
ThreadItem *item = MT_INTERFACE->GetCallingThread ();
|
|
|
|
ReleaseResourceLock (LOCK_THREAD_LIST, READ_LOCK, "__pthread_sigmask");
|
|
|
|
|
|
|
|
// lock this myself, for the use of thread2signal
|
|
|
|
// two differt kills might clash: FIX ME
|
|
|
|
|
|
|
|
if (item->sigs)
|
|
|
|
myself->setthread2signal (item);
|
|
|
|
|
|
|
|
int rval = sigprocmask (operation, set, old_set);
|
|
|
|
|
|
|
|
// unlock this myself
|
|
|
|
|
|
|
|
return rval;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* ID */
|
|
|
|
pthread_t
|
|
|
|
__pthread_self ()
|
|
|
|
{
|
|
|
|
SetResourceLock (LOCK_THREAD_LIST, READ_LOCK, "__pthread_self");
|
|
|
|
|
|
|
|
ThreadItem *item = MT_INTERFACE->GetCallingThread ();
|
|
|
|
|
|
|
|
ReleaseResourceLock (LOCK_THREAD_LIST, READ_LOCK, "__pthread_self");
|
|
|
|
return (pthread_t) item->Id ();
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
__pthread_equal (pthread_t * t1, pthread_t * t2)
|
|
|
|
{
|
|
|
|
return (*t1 - *t2);
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Mutexes */
|
|
|
|
|
|
|
|
int
|
2000-02-24 04:53:22 +01:00
|
|
|
__pthread_mutex_init (pthread_mutex_t * mutex, const pthread_mutexattr_t */*_attr*/)
|
2000-02-17 20:38:33 +01:00
|
|
|
{
|
|
|
|
SetResourceLock (LOCK_MUTEX_LIST, WRITE_LOCK | READ_LOCK, "__pthread_mutex_init");
|
|
|
|
|
|
|
|
MutexItem *item = MT_INTERFACE->CreateMutex (mutex);
|
|
|
|
|
|
|
|
CHECKITEM (LOCK_MUTEX_LIST, WRITE_LOCK | READ_LOCK, "__pthread_mutex_init");
|
|
|
|
|
|
|
|
ReleaseResourceLock (LOCK_MUTEX_LIST, WRITE_LOCK | READ_LOCK, "__pthread_mutex_init");
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
__pthread_mutex_lock (pthread_mutex_t * mutex)
|
|
|
|
{
|
|
|
|
GETMUTEX ("_ptherad_mutex_lock");
|
|
|
|
|
|
|
|
item->Lock ();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
__pthread_mutex_trylock (pthread_mutex_t * mutex)
|
|
|
|
{
|
|
|
|
GETMUTEX ("_ptherad_mutex_lock");
|
|
|
|
|
|
|
|
if (item->TryLock () == WAIT_TIMEOUT)
|
|
|
|
return EBUSY;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
__pthread_mutex_unlock (pthread_mutex_t * mutex)
|
|
|
|
{
|
|
|
|
GETMUTEX ("_ptherad_mutex_lock");
|
|
|
|
|
|
|
|
item->UnLock ();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
__pthread_mutex_destroy (pthread_mutex_t * mutex)
|
|
|
|
{
|
|
|
|
SetResourceLock (LOCK_MUTEX_LIST, READ_LOCK | WRITE_LOCK, "__pthread_mutex_destroy");
|
|
|
|
|
|
|
|
MutexItem *item = MT_INTERFACE->GetMutex (mutex);
|
|
|
|
|
|
|
|
CHECKITEM (LOCK_MUTEX_LIST, WRITE_LOCK | READ_LOCK, "__pthread_mutex_init");
|
|
|
|
|
|
|
|
item->Destroy ();
|
|
|
|
|
|
|
|
MT_INTERFACE->ReleaseItem (item);
|
|
|
|
|
|
|
|
ReleaseResourceLock (LOCK_MUTEX_LIST, READ_LOCK | WRITE_LOCK, "__pthread_mutex_destroy");
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
/* Semaphores */
|
|
|
|
int
|
|
|
|
__sem_init (sem_t * sem, int pshared, unsigned int value)
|
|
|
|
{
|
|
|
|
SetResourceLock (LOCK_SEM_LIST, READ_LOCK | WRITE_LOCK, "__sem_init");
|
|
|
|
|
|
|
|
SemaphoreItem *item = MT_INTERFACE->CreateSemaphore (sem, pshared, value);
|
|
|
|
|
|
|
|
CHECKITEM (LOCK_SEM_LIST, READ_LOCK | WRITE_LOCK, "__sem_init");
|
|
|
|
|
|
|
|
ReleaseResourceLock (LOCK_SEM_LIST, READ_LOCK | WRITE_LOCK, "__sem_init");
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
__sem_destroy (sem_t * sem)
|
|
|
|
{
|
|
|
|
SetResourceLock (LOCK_SEM_LIST, READ_LOCK | WRITE_LOCK, "__sem_destroy");
|
|
|
|
|
|
|
|
SemaphoreItem *item = MT_INTERFACE->GetSemaphore (sem);
|
|
|
|
|
|
|
|
CHECKITEM (LOCK_SEM_LIST, READ_LOCK | WRITE_LOCK, "__sem_init");
|
|
|
|
|
|
|
|
item->Destroy ();
|
|
|
|
|
|
|
|
MT_INTERFACE->ReleaseItem (item);
|
|
|
|
|
|
|
|
ReleaseResourceLock (LOCK_SEM_LIST, READ_LOCK | WRITE_LOCK, "__sem_destroy");
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
__sem_wait (sem_t * sem)
|
|
|
|
{
|
|
|
|
GETSEMA ("__sem_wait");
|
|
|
|
|
|
|
|
item->Wait ();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
__sem_trywait (sem_t * sem)
|
|
|
|
{
|
|
|
|
GETSEMA ("__sem_trywait");
|
|
|
|
|
|
|
|
if (item->TryWait () == WAIT_TIMEOUT)
|
|
|
|
return EAGAIN;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
int
|
|
|
|
__sem_post (sem_t * sem)
|
|
|
|
{
|
|
|
|
GETSEMA ("__sem_post");
|
|
|
|
|
|
|
|
item->Post ();
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
#else
|
|
|
|
|
|
|
|
// empty functions needed when makeing the dll without mt_safe support
|
|
|
|
extern "C"
|
|
|
|
{
|
|
|
|
int __pthread_create (pthread_t *, const pthread_attr_t *, TFD (start_routine), void *arg)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
};
|
|
|
|
int __pthread_attr_init (pthread_attr_t * attr)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
};
|
|
|
|
int __pthread_attr_destroy (pthread_attr_t * attr)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
};
|
|
|
|
int __pthread_attr_setstacksize (pthread_attr_t * attr, size_t size)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
};
|
|
|
|
int __pthread_attr_getstacksize (pthread_attr_t * attr, size_t * size)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
};
|
|
|
|
/*
|
|
|
|
__pthread_attr_setstackaddr(...){ return -1; };
|
|
|
|
__pthread_attr_getstackaddr(...){ return -1; };
|
|
|
|
*/
|
|
|
|
int __pthread_exit (void *value_ptr)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
};
|
|
|
|
|
|
|
|
int __pthread_join(pthread_t thread_id, void **return_val)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long __pthread_getsequence_np (pthread_t * thread)
|
|
|
|
{
|
|
|
|
return 0;
|
|
|
|
};
|
|
|
|
int __pthread_key_create (pthread_key_t * key)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
};
|
|
|
|
int __pthread_key_delete (pthread_key_t * key)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
};
|
|
|
|
int __pthread_setspecific (pthread_key_t * key, const void *value)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
};
|
|
|
|
void *__pthread_getspecific (pthread_key_t * key)
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
};
|
|
|
|
int __pthread_kill (pthread_t * thread, int sig)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
};
|
|
|
|
int __pthread_sigmask (int operation, const sigset_t * set, sigset_t * old_set)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
};
|
|
|
|
pthread_t __pthread_self ()
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
};
|
|
|
|
int __pthread_equal (pthread_t * t1, pthread_t * t2)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
};
|
|
|
|
int __pthread_mutex_init (pthread_mutex_t *, const pthread_mutexattr_t *)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
};
|
|
|
|
int __pthread_mutex_lock (pthread_mutex_t *)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
};
|
|
|
|
int __pthread_mutex_trylock (pthread_mutex_t *)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
};
|
|
|
|
int __pthread_mutex_unlock (pthread_mutex_t *)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
};
|
|
|
|
int __pthread_mutex_destroy (pthread_mutex_t *)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
};
|
|
|
|
int __sem_init (sem_t * sem, int pshared, unsigned int value)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
};
|
|
|
|
int __sem_destroy (sem_t * sem)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
};
|
|
|
|
int __sem_wait (sem_t * sem)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
};
|
|
|
|
int __sem_trywait (sem_t * sem)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
};
|
|
|
|
int __sem_post (sem_t * sem)
|
|
|
|
{
|
|
|
|
return -1;
|
|
|
|
};
|
|
|
|
struct _reent *_reent_clib ()
|
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif // MT_SAFE
|