1002 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			1002 lines
		
	
	
		
			21 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
/* 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
 | 
						|
__pthread_attr_destroy (pthread_attr_t * /*attr*/)
 | 
						|
{
 | 
						|
  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
 | 
						|
__pthread_key_create (pthread_key_t */*key*/)
 | 
						|
{
 | 
						|
  NOT_IMP ("_p_key_create\n");
 | 
						|
};
 | 
						|
 | 
						|
int
 | 
						|
__pthread_key_delete (pthread_key_t */*key*/)
 | 
						|
{
 | 
						|
  NOT_IMP ("_p_key_delete\n");
 | 
						|
};
 | 
						|
int
 | 
						|
__pthread_setspecific (pthread_key_t */*key*/, const void */*value*/)
 | 
						|
{
 | 
						|
  NOT_IMP ("_p_key_setsp\n");
 | 
						|
};
 | 
						|
void *
 | 
						|
__pthread_getspecific (pthread_key_t */*key*/)
 | 
						|
{
 | 
						|
  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);
 | 
						|
 | 
						|
  int rval = sig_send (myself, sig);
 | 
						|
 | 
						|
// 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
 | 
						|
__pthread_mutex_init (pthread_mutex_t * mutex, const pthread_mutexattr_t */*_attr*/)
 | 
						|
{
 | 
						|
  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
 |