mirror of
https://github.com/2003scape/deep-c-rsc.git
synced 2024-03-22 05:49:51 -04:00
1440 lines
36 KiB
C
1440 lines
36 KiB
C
![]() |
/*
|
||
|
* @(#) tpthread.c - T-PThread source.
|
||
|
* Copyright (C) 2006-2007 Ivan Maidanski <ivmai@mail.ru> All rights reserved.
|
||
|
**
|
||
|
* Version: 1.2
|
||
|
* See also files: pthread.h, sched.h
|
||
|
* Required: any ANSI C compiler.
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* This is free software; you can redistribute it and/or modify
|
||
|
* it under the terms of the GNU General Public License as published by
|
||
|
* the Free Software Foundation; either version 2, or (at your option)
|
||
|
* any later version.
|
||
|
**
|
||
|
* This software is distributed in the hope that it will be useful, but
|
||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||
|
* General Public License (GPL) for more details.
|
||
|
**
|
||
|
* Linking this library statically or dynamically with other modules is
|
||
|
* making a combined work based on this library. Thus, the terms and
|
||
|
* conditions of the GNU General Public License cover the whole
|
||
|
* combination.
|
||
|
**
|
||
|
* As a special exception, the copyright holders of this library give you
|
||
|
* permission to link this library with independent modules to produce an
|
||
|
* executable, regardless of the license terms of these independent
|
||
|
* modules, and to copy and distribute the resulting executable under
|
||
|
* terms of your choice, provided that you also meet, for each linked
|
||
|
* independent module, the terms and conditions of the license of that
|
||
|
* module. An independent module is a module which is not derived from
|
||
|
* or based on this library. If you modify this library, you may extend
|
||
|
* this exception to your version of the library, but you are not
|
||
|
* obligated to do so. If you do not wish to do so, delete this
|
||
|
* exception statement from your version.
|
||
|
*/
|
||
|
|
||
|
/* T-PThread is a tiny portable POSIX threads library */
|
||
|
/* T-PThread API is a subset of the standard POSIX Threads API */
|
||
|
|
||
|
/* The implemented scheduler is non-preemptive (cooperative) */
|
||
|
|
||
|
/*
|
||
|
* Tested with:
|
||
|
* Linux RedHat i386 (-O2 -DPTHREAD_FASTCALL= -DPTHREAD_CPUSTATE_SPOFF=16),
|
||
|
* DJGPP (-O2 -Wall -DPTHREAD_FASTCALL= -DPTHREAD_USE_GETTIMEOFDAY),
|
||
|
* EMX (-O2 -DPTHREAD_FASTCALL= -DPTHREAD_USE_SIGACTION -DPTHREAD_CPUSTATE_SPOFF=12),
|
||
|
* Watcom i386 (-ox -DPTHREAD_NO_SIGSET -DPTHREAD_CPUSTATE_SPOFF=28),
|
||
|
* DMC x32/ss=ds (-o -mx -DPTHREAD_NO_SIGSET -DPTHREAD_CPUSTATE_SPOFF=12),
|
||
|
* Borland C16 (-Ox -ml -DPTHREAD_NO_SIGSET -D__esp=j_sp),
|
||
|
* Borland C32 (-Ox -DPTHREAD_NO_SIGSET -D__esp=j_esp),
|
||
|
* MS C16 (-Ox -AM -DPTHREAD_NO_SIGSET -DPTHREAD_CPUSTATE_SPOFF=6),
|
||
|
* MS C i386 (-Ox -DPTHREAD_NO_SIGSET -D__jmp_buf=__JUMP_BUFFER -D__esp=Esp).
|
||
|
*/
|
||
|
|
||
|
/*
|
||
|
* Control macros: PTHREAD_NO_SIGSET, PTHREAD_USE_GETTIMEOFDAY,
|
||
|
* PTHREAD_USE_SIGACTION.
|
||
|
* Macros for tuning (also see in pthread.h): PTHREAD_CORE_API,
|
||
|
* PTHREAD_CORE_CALL, PTHREAD_CORE_FREE, PTHREAD_CORE_MALLOC,
|
||
|
* PTHREAD_CPUSTATE_SIZE, PTHREAD_CPUSTATE_SPOFF, PTHREAD_DATASTATIC,
|
||
|
* PTHREAD_FASTCALL, PTHREAD_SCHED_MAXPRIO, PTHREAD_STACK_DEFSIZE,
|
||
|
* PTHREAD_STACK_GAPWORDS, PTHREAD_STACK_MINSIZE, PTHREAD_STACK_REDSIZE,
|
||
|
* PTHREAD_STATIC.
|
||
|
*/
|
||
|
|
||
|
/* Compilation note: turn off stack overflow checking globally */
|
||
|
|
||
|
#ifndef _STDLIB_H
|
||
|
#include <stdlib.h>
|
||
|
/* void abort(void); */
|
||
|
/* void exit(int); */
|
||
|
/* void free(void *); */
|
||
|
/* void *malloc(size_t); */
|
||
|
#endif
|
||
|
|
||
|
#ifndef _ERRNO_H
|
||
|
#include <errno.h>
|
||
|
/* int errno; */
|
||
|
#endif
|
||
|
|
||
|
#ifndef _SIGNAL_H
|
||
|
#include <signal.h>
|
||
|
#endif
|
||
|
|
||
|
#ifdef PTHREAD_USE_GETTIMEOFDAY
|
||
|
|
||
|
#ifndef _SYS_TIME_H
|
||
|
#include <sys/time.h>
|
||
|
/* int gettimeofday(struct timeval *, struct timezone *); */
|
||
|
#endif
|
||
|
|
||
|
#else /* PTHREAD_USE_GETTIMEOFDAY */
|
||
|
|
||
|
#ifndef _SYS_TIMEB_H
|
||
|
#include <sys/timeb.h>
|
||
|
/* void ftime(struct timeb *); */
|
||
|
#endif
|
||
|
|
||
|
#endif /* ! PTHREAD_USE_GETTIMEOFDAY */
|
||
|
|
||
|
#include "pthread.h"
|
||
|
|
||
|
#include "sched.h"
|
||
|
|
||
|
#ifndef PTHREAD_DATASTATIC
|
||
|
#define PTHREAD_DATASTATIC static
|
||
|
#endif
|
||
|
|
||
|
#ifndef PTHREAD_STATIC
|
||
|
#define PTHREAD_STATIC static
|
||
|
#endif
|
||
|
|
||
|
#ifndef PTHREAD_FASTCALL
|
||
|
#define PTHREAD_FASTCALL __fastcall
|
||
|
#endif
|
||
|
|
||
|
#ifdef PTHREAD_CPUSTATE_SIZE
|
||
|
|
||
|
void pthread_sched_done(void);
|
||
|
int pthread_sched_init(void);
|
||
|
void pthread_sched_switch(void *pstate, void *pnewstate, void *stackptr);
|
||
|
|
||
|
#else /* PTHREAD_CPUSTATE_SIZE */
|
||
|
|
||
|
#ifndef _SETJMP_H
|
||
|
#include <setjmp.h>
|
||
|
#endif
|
||
|
|
||
|
#ifdef PTHREAD_NO_SIGSET
|
||
|
|
||
|
/* #include <setjmp.h> */
|
||
|
/* void longjmp(jmp_buf, int); */
|
||
|
/* int setjmp(jmp_buf); */
|
||
|
|
||
|
#define PTHREAD_CPUSTATE_SIZE sizeof(jmp_buf)
|
||
|
#define PTHREAD_CPUSTATE_SETJMP(buf) setjmp(buf)
|
||
|
#define PTHREAD_CPUSTATE_LONGJMP(buf) longjmp(buf, 1)
|
||
|
|
||
|
#else /* PTHREAD_NO_SIGSET */
|
||
|
|
||
|
/* #include <setjmp.h> */
|
||
|
/* void siglongjmp(sigjmp_buf, int); */
|
||
|
/* int sigsetjmp(sigjmp_buf, int); */
|
||
|
|
||
|
#define PTHREAD_CPUSTATE_SIZE sizeof(sigjmp_buf)
|
||
|
#define PTHREAD_CPUSTATE_SETJMP(buf) sigsetjmp(buf, 1)
|
||
|
#define PTHREAD_CPUSTATE_LONGJMP(buf) siglongjmp(buf, 1)
|
||
|
|
||
|
#endif /* ! PTHREAD_NO_SIGSET */
|
||
|
|
||
|
#ifndef PTHREAD_CPUSTATE_SPOFF
|
||
|
#define PTHREAD_CPUSTATE_SPOFF (unsigned)((char *)&((struct __jmp_buf *)0)->__esp - (char *)0)
|
||
|
#endif
|
||
|
|
||
|
void pthread_sched_launcher(void);
|
||
|
|
||
|
PTHREAD_STATIC void pthread_sched_done(void)
|
||
|
{
|
||
|
/* dummy */
|
||
|
}
|
||
|
|
||
|
PTHREAD_STATIC int pthread_sched_init(void)
|
||
|
{
|
||
|
/* dummy */
|
||
|
/* atexit(pthread_sched_done); */
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
PTHREAD_STATIC void pthread_sched_switch(void *pstate, void *pnewstate,
|
||
|
void *stackptr)
|
||
|
{
|
||
|
if (!PTHREAD_CPUSTATE_SETJMP(pstate))
|
||
|
{
|
||
|
if (stackptr)
|
||
|
{
|
||
|
int i = ((PTHREAD_CPUSTATE_SIZE - 1) / sizeof(int)) * sizeof(int);
|
||
|
do
|
||
|
{
|
||
|
*(volatile int *)((char *)pnewstate + i) =
|
||
|
*(volatile int *)((char *)pstate + i);
|
||
|
} while ((i -= sizeof(int)) >= 0);
|
||
|
*(void *volatile *)((char *)pnewstate + PTHREAD_CPUSTATE_SPOFF) = stackptr;
|
||
|
}
|
||
|
PTHREAD_CPUSTATE_LONGJMP(pnewstate);
|
||
|
}
|
||
|
pthread_sched_launcher();
|
||
|
}
|
||
|
|
||
|
#endif /* ! PTHREAD_CPUSTATE_SIZE */
|
||
|
|
||
|
#ifndef NULL
|
||
|
#define NULL (void *)0
|
||
|
#endif
|
||
|
|
||
|
#ifndef PTHREAD_CORE_API
|
||
|
#define PTHREAD_CORE_API PTHREAD_API
|
||
|
#endif
|
||
|
|
||
|
#ifndef PTHREAD_CORE_CALL
|
||
|
#define PTHREAD_CORE_CALL PTHREAD_CALL
|
||
|
#endif
|
||
|
|
||
|
#ifdef PTHREAD_CORE_MALLOC
|
||
|
PTHREAD_CORE_API void *PTHREAD_CORE_CALL PTHREAD_CORE_MALLOC(size_t size);
|
||
|
#else
|
||
|
#define PTHREAD_CORE_MALLOC malloc
|
||
|
#endif
|
||
|
|
||
|
#ifdef PTHREAD_CORE_FREE
|
||
|
PTHREAD_CORE_API void PTHREAD_CORE_CALL PTHREAD_CORE_FREE(void *ptr);
|
||
|
#else
|
||
|
#define PTHREAD_CORE_FREE free
|
||
|
#endif
|
||
|
|
||
|
#ifndef PTHREAD_SCHED_MAXPRIO
|
||
|
#define PTHREAD_SCHED_MAXPRIO 99
|
||
|
#endif
|
||
|
|
||
|
#ifndef PTHREAD_STACK_REDSIZE
|
||
|
#define PTHREAD_STACK_REDSIZE 0x200
|
||
|
#endif
|
||
|
|
||
|
#ifndef PTHREAD_STACK_MINSIZE
|
||
|
#define PTHREAD_STACK_MINSIZE 0x1000
|
||
|
#endif
|
||
|
|
||
|
#ifndef PTHREAD_STACK_DEFSIZE
|
||
|
#define PTHREAD_STACK_DEFSIZE 0x7FF0
|
||
|
#endif
|
||
|
|
||
|
#ifndef PTHREAD_STACK_GAPWORDS
|
||
|
#define PTHREAD_STACK_GAPWORDS 8
|
||
|
#endif
|
||
|
|
||
|
#ifdef PTHREAD_USE_GETTIMEOFDAY
|
||
|
|
||
|
#define PTHREAD_CURTIME_T struct timeval
|
||
|
#define PTHREAD_CURTIME_GET(ptv, pts) (gettimeofday((void *)(ptv), NULL), (pts)->tv_sec = (time_t)(ptv)->tv_sec, (void)((pts)->tv_nsec = (long)(ptv)->tv_usec * 1000L))
|
||
|
|
||
|
#else /* PTHREAD_USE_GETTIMEOFDAY */
|
||
|
|
||
|
#define PTHREAD_CURTIME_T struct timeb
|
||
|
#define PTHREAD_CURTIME_GET(ptv, pts) (ftime(ptv), (pts)->tv_sec = (ptv)->time, (void)((pts)->tv_nsec = (long)(ptv)->millitm * (1000L * 1000L)))
|
||
|
|
||
|
#endif /* ! PTHREAD_USE_GETTIMEOFDAY */
|
||
|
|
||
|
#ifdef PTHREAD_USE_SIGACTION
|
||
|
|
||
|
/* #include <signal.h> */
|
||
|
/* int sigaction(int, const struct sigaction *, struct sigaction *); */
|
||
|
|
||
|
#define PTHREAD_SIGRAISE_T struct sigaction
|
||
|
#define PTHREAD_SIG_RAISE(signum, poact) (sigaction(signum, NULL, poact) ? -1 : (poact)->sa_handler != SIG_DFL && (poact)->sa_handler != SIG_ERR && (poact)->sa_handler != SIG_IGN ? ((*(poact)->sa_handler)(signum), 0) : 0)
|
||
|
#define PTHREAD_SIG_VALID(signum) (!sigaction(signum, NULL, NULL))
|
||
|
|
||
|
#else /* PTHREAD_USE_SIGACTION */
|
||
|
|
||
|
/* #include <signal.h> */
|
||
|
/* int raise(int); */
|
||
|
|
||
|
#ifndef NSIG
|
||
|
#ifdef _NSIG
|
||
|
#define NSIG _NSIG
|
||
|
#else
|
||
|
#define NSIG 256
|
||
|
#endif
|
||
|
#endif
|
||
|
|
||
|
#define PTHREAD_SIGRAISE_T int
|
||
|
#define PTHREAD_SIG_RAISE(signum, poact) (*(poact) = (signum), raise(*(poact)))
|
||
|
#define PTHREAD_SIG_VALID(signum) ((signum) > 0 && (signum) < NSIG)
|
||
|
|
||
|
#endif /* ! PTHREAD_USE_SIGACTION */
|
||
|
|
||
|
#define PTHREAD_PROCESS_ABORT abort()
|
||
|
#define PTHREAD_PROCESS_EXIT exit(0)
|
||
|
|
||
|
#define PTHREAD_ERRNO_SET(errcode) (void)(errno = (errcode))
|
||
|
|
||
|
#define PTHREAD_SCHEDPRIO_MIN(policy) ((policy) != SCHED_OTHER ? 1 : 0)
|
||
|
#define PTHREAD_SCHEDPRIO_MAX(policy) ((policy) != SCHED_OTHER ? PTHREAD_SCHED_MAXPRIO : 0)
|
||
|
|
||
|
#define PTHREAD_SCHEDPOL_TERMINATED -1
|
||
|
|
||
|
#define PTHREAD_DESCR_TID(thr) ((pthread_t)((volatile void *)(thr)))
|
||
|
#define PTHREAD_TID_DESCR(pthread) ((pthread_descr_t)((volatile void *)(pthread)))
|
||
|
|
||
|
#define PTHREAD_DESCR_MAGIC (int)0x50546872L /* 'PThr' */
|
||
|
#define PTHREAD_DESCR_VALID(thr) ((thr) != NULL && (thr) != (pthread_descr_t)-1L && (thr)->p_magic == PTHREAD_DESCR_MAGIC)
|
||
|
|
||
|
#define PTHREAD_SCHEDCMD_WAIT 1
|
||
|
#define PTHREAD_SCHEDCMD_YIELD 2
|
||
|
|
||
|
typedef void *(PTHREAD_USERCALL *pthread_startrtn_t)(void *);
|
||
|
typedef void (PTHREAD_USERCALL *pthread_destr_t)(void *);
|
||
|
|
||
|
struct pthread_descr_s;
|
||
|
typedef struct pthread_descr_s *pthread_descr_t;
|
||
|
|
||
|
struct pthread_descr_s
|
||
|
{
|
||
|
int p_magic;
|
||
|
int p_suspended;
|
||
|
pthread_descr_t p_nextlive;
|
||
|
pthread_descr_t p_prevlive;
|
||
|
int p_priority;
|
||
|
int p_policy;
|
||
|
int p_signum;
|
||
|
size_t p_stacksize;
|
||
|
void *p_stackbase;
|
||
|
pthread_mutex_t *p_condmutex;
|
||
|
struct timespec p_waketime;
|
||
|
pthread_descr_t p_nextwaiting;
|
||
|
pthread_descr_t p_joining;
|
||
|
int p_mutexcount;
|
||
|
int p_errno;
|
||
|
void *p_retval;
|
||
|
pthread_startrtn_t p_startrtn;
|
||
|
long p_cpustate[(PTHREAD_CPUSTATE_SIZE + sizeof(long) - 1) / sizeof(long)];
|
||
|
void *p_specific[PTHREAD_KEYS_MAX];
|
||
|
};
|
||
|
|
||
|
volatile unsigned pthread_sched_stopped = 0;
|
||
|
|
||
|
PTHREAD_DATASTATIC pthread_descr_t pthread_descr_pendremove = NULL;
|
||
|
|
||
|
PTHREAD_DATASTATIC struct pthread_descr_s pthread_descr_main =
|
||
|
{
|
||
|
PTHREAD_DESCR_MAGIC,
|
||
|
0,
|
||
|
&pthread_descr_main,
|
||
|
&pthread_descr_main,
|
||
|
0,
|
||
|
SCHED_OTHER,
|
||
|
-1,
|
||
|
0,
|
||
|
NULL,
|
||
|
NULL,
|
||
|
{ 0, 0 },
|
||
|
NULL,
|
||
|
NULL,
|
||
|
0,
|
||
|
0,
|
||
|
NULL,
|
||
|
(pthread_startrtn_t)0,
|
||
|
{ 0 },
|
||
|
{ NULL }
|
||
|
};
|
||
|
|
||
|
PTHREAD_DATASTATIC pthread_descr_t pthread_descr_self = &pthread_descr_main;
|
||
|
|
||
|
PTHREAD_DATASTATIC pthread_destr_t pthread_keys_destr[PTHREAD_KEYS_MAX] =
|
||
|
{
|
||
|
(pthread_destr_t)0
|
||
|
};
|
||
|
|
||
|
int pthread_noop_access(void *ptr)
|
||
|
{
|
||
|
return *(volatile char *)ptr;
|
||
|
}
|
||
|
|
||
|
int pthread_stack_getptr(void **pstackptr)
|
||
|
{
|
||
|
volatile void *stackptr;
|
||
|
stackptr = &stackptr;
|
||
|
pthread_noop_access((void *)&stackptr);
|
||
|
*pstackptr = (void *)stackptr;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
void pthread_sched_launcher(void)
|
||
|
{
|
||
|
pthread_descr_t self = pthread_descr_self;
|
||
|
pthread_startrtn_t rtn;
|
||
|
void *arg;
|
||
|
if ((rtn = self->p_startrtn) != (pthread_startrtn_t)0)
|
||
|
{
|
||
|
arg = self->p_retval;
|
||
|
*(volatile pthread_startrtn_t *)&self->p_startrtn = (pthread_startrtn_t)0;
|
||
|
self->p_retval = NULL;
|
||
|
pthread_sched_stopped = 0;
|
||
|
pthread_exit((*rtn)(arg));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PTHREAD_STATIC void PTHREAD_FASTCALL pthread_sched_coresleep(
|
||
|
struct timespec *pts)
|
||
|
{
|
||
|
struct timespec ts2;
|
||
|
PTHREAD_CURTIME_T tv;
|
||
|
do
|
||
|
{
|
||
|
PTHREAD_CURTIME_GET(&tv, &ts2);
|
||
|
} while ((long)pts->tv_sec - (long)ts2.tv_sec > 0 ||
|
||
|
(pts->tv_sec == ts2.tv_sec && pts->tv_nsec > ts2.tv_nsec));
|
||
|
}
|
||
|
|
||
|
PTHREAD_STATIC void PTHREAD_FASTCALL pthread_sched_resume(pthread_descr_t thr)
|
||
|
{
|
||
|
if (thr->p_suspended && thr->p_policy != PTHREAD_SCHEDPOL_TERMINATED)
|
||
|
thr->p_suspended = 0;
|
||
|
}
|
||
|
|
||
|
PTHREAD_STATIC pthread_descr_t PTHREAD_FASTCALL pthread_sched_findnext(void)
|
||
|
{
|
||
|
pthread_descr_t self = pthread_descr_self;
|
||
|
pthread_descr_t thr = self;
|
||
|
pthread_descr_t thr2 = NULL;
|
||
|
struct timespec ts2;
|
||
|
PTHREAD_CURTIME_T tv;
|
||
|
long diff;
|
||
|
ts2.tv_sec = 0;
|
||
|
ts2.tv_nsec = 0;
|
||
|
do
|
||
|
{
|
||
|
if (!(thr = thr->p_nextlive)->p_suspended)
|
||
|
break;
|
||
|
if (thr->p_waketime.tv_sec && (thr2 == NULL || ((diff =
|
||
|
(long)thr->p_waketime.tv_sec - (long)thr2->p_waketime.tv_sec) <= 0 &&
|
||
|
(diff || thr->p_waketime.tv_nsec < thr2->p_waketime.tv_nsec))))
|
||
|
{
|
||
|
if (thr2 == NULL)
|
||
|
PTHREAD_CURTIME_GET(&tv, &ts2);
|
||
|
thr2 = thr;
|
||
|
if ((diff = (long)thr->p_waketime.tv_sec - (long)ts2.tv_sec) <= 0 &&
|
||
|
(diff || thr->p_waketime.tv_nsec <= ts2.tv_nsec))
|
||
|
{
|
||
|
pthread_sched_resume(thr);
|
||
|
thr->p_waketime.tv_sec = 0;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
} while (thr != self);
|
||
|
if (thr2 != NULL && thr->p_suspended)
|
||
|
thr = thr2;
|
||
|
return thr;
|
||
|
}
|
||
|
|
||
|
PTHREAD_STATIC void PTHREAD_FASTCALL pthread_sched_enable(int schedcmd)
|
||
|
{
|
||
|
pthread_descr_t self = pthread_descr_self;
|
||
|
pthread_descr_t thr;
|
||
|
void *stackptr;
|
||
|
int signum = -1;
|
||
|
PTHREAD_SIGRAISE_T oact;
|
||
|
if (self->p_stacksize)
|
||
|
{
|
||
|
(void)pthread_stack_getptr(&stackptr);
|
||
|
if (stackptr < (void *)(&stackptr) ?
|
||
|
(void *)((volatile char *)self->p_stackbase +
|
||
|
(size_t)PTHREAD_STACK_REDSIZE) > stackptr :
|
||
|
(void *)((volatile char *)self->p_stackbase + (self->p_stacksize -
|
||
|
(size_t)PTHREAD_STACK_REDSIZE)) <= stackptr)
|
||
|
{
|
||
|
pthread_sched_done();
|
||
|
PTHREAD_PROCESS_ABORT;
|
||
|
}
|
||
|
}
|
||
|
if (schedcmd == PTHREAD_SCHEDCMD_WAIT || pthread_sched_stopped == 1)
|
||
|
{
|
||
|
if (schedcmd)
|
||
|
self->p_suspended = 1;
|
||
|
thr = self;
|
||
|
if (pthread_sched_stopped == 1)
|
||
|
thr = pthread_sched_findnext();
|
||
|
if (schedcmd == PTHREAD_SCHEDCMD_YIELD)
|
||
|
{
|
||
|
self->p_suspended = 0;
|
||
|
if (thr->p_suspended)
|
||
|
thr = self;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (thr->p_suspended)
|
||
|
{
|
||
|
if (!thr->p_waketime.tv_sec)
|
||
|
{
|
||
|
pthread_sched_done();
|
||
|
if (self->p_nextlive != self ||
|
||
|
self->p_policy != PTHREAD_SCHEDPOL_TERMINATED)
|
||
|
PTHREAD_PROCESS_ABORT;
|
||
|
PTHREAD_PROCESS_EXIT;
|
||
|
}
|
||
|
pthread_sched_coresleep(&thr->p_waketime);
|
||
|
thr->p_suspended = 0;
|
||
|
thr->p_waketime.tv_sec = 0;
|
||
|
}
|
||
|
}
|
||
|
if (thr != self)
|
||
|
{
|
||
|
stackptr = NULL;
|
||
|
if (thr->p_startrtn)
|
||
|
{
|
||
|
(void)pthread_stack_getptr(&stackptr);
|
||
|
stackptr = (void *)((volatile char *)thr->p_stackbase +
|
||
|
(stackptr < (void *)(&self) ? thr->p_stacksize -
|
||
|
(PTHREAD_STACK_GAPWORDS + 1) * sizeof(long) :
|
||
|
PTHREAD_STACK_GAPWORDS * sizeof(long)));
|
||
|
}
|
||
|
*(volatile int *)&self->p_errno = errno;
|
||
|
*(volatile pthread_descr_t *)&pthread_descr_self = thr;
|
||
|
pthread_sched_switch(&self->p_cpustate, &thr->p_cpustate, stackptr);
|
||
|
signum = self->p_signum;
|
||
|
self->p_signum = -1;
|
||
|
PTHREAD_ERRNO_SET(self->p_errno);
|
||
|
}
|
||
|
}
|
||
|
pthread_sched_stopped--;
|
||
|
if (signum != -1 && PTHREAD_SIG_RAISE(signum, &oact))
|
||
|
PTHREAD_ERRNO_SET(self->p_errno);
|
||
|
}
|
||
|
|
||
|
PTHREAD_STATIC void PTHREAD_FASTCALL pthread_sched_disable(void)
|
||
|
{
|
||
|
pthread_sched_stopped++;
|
||
|
}
|
||
|
|
||
|
PTHREAD_STATIC void PTHREAD_FASTCALL pthread_descr_destroy(
|
||
|
pthread_descr_t thr)
|
||
|
{
|
||
|
pthread_descr_t thr2 = thr->p_nextlive;
|
||
|
thr->p_magic = 0;
|
||
|
(thr2->p_prevlive = thr->p_prevlive)->p_nextlive = thr2;
|
||
|
thr->p_joining = NULL;
|
||
|
thr->p_nextlive = NULL;
|
||
|
thr->p_prevlive = NULL;
|
||
|
}
|
||
|
|
||
|
PTHREAD_STATIC void PTHREAD_FASTCALL pthread_descr_free(pthread_descr_t thr)
|
||
|
{
|
||
|
if (thr != &pthread_descr_main)
|
||
|
{
|
||
|
PTHREAD_CORE_FREE(thr->p_stackbase);
|
||
|
if (!thr->p_mutexcount && thr->p_nextwaiting == NULL)
|
||
|
PTHREAD_CORE_FREE(thr);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PTHREAD_STATIC void PTHREAD_FASTCALL pthread_descr_clearpending(void)
|
||
|
{
|
||
|
pthread_descr_t thr;
|
||
|
while ((thr = pthread_descr_pendremove) != NULL)
|
||
|
{
|
||
|
pthread_descr_pendremove = NULL;
|
||
|
pthread_descr_destroy(thr);
|
||
|
pthread_sched_enable(0);
|
||
|
pthread_descr_free(thr);
|
||
|
pthread_sched_disable();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
PTHREAD_STATIC void PTHREAD_FASTCALL pthread_keys_destroy(void)
|
||
|
{
|
||
|
pthread_descr_t self = pthread_descr_self;
|
||
|
void *val;
|
||
|
pthread_destr_t destr_rtn;
|
||
|
unsigned i;
|
||
|
int found;
|
||
|
int retry = PTHREAD_DESTRUCTOR_ITERATIONS;
|
||
|
do
|
||
|
{
|
||
|
found = 0;
|
||
|
for (i = 0; i < PTHREAD_KEYS_MAX; i++)
|
||
|
if ((destr_rtn = pthread_keys_destr[i]) != (pthread_destr_t)0 &&
|
||
|
destr_rtn != (pthread_destr_t)-1L &&
|
||
|
(val = self->p_specific[i]) != NULL)
|
||
|
{
|
||
|
found = 1;
|
||
|
self->p_specific[i] = NULL;
|
||
|
(*destr_rtn)(val);
|
||
|
}
|
||
|
} while (found && --retry > 0);
|
||
|
}
|
||
|
|
||
|
PTHREAD_STATIC void PTHREAD_FASTCALL pthread_queue_add(
|
||
|
struct _pthread_queue *pqueue, pthread_descr_t thr)
|
||
|
{
|
||
|
pthread_descr_t tail;
|
||
|
thr->p_nextwaiting = thr;
|
||
|
if ((tail = (pthread_descr_t)((volatile void *)pqueue->tail)) != NULL)
|
||
|
{
|
||
|
thr->p_nextwaiting = tail->p_nextwaiting;
|
||
|
tail->p_nextwaiting = thr;
|
||
|
}
|
||
|
pqueue->tail = (_pthread_descr)((volatile void *)thr);
|
||
|
}
|
||
|
|
||
|
PTHREAD_STATIC void *PTHREAD_FASTCALL pthread_queue_remove(
|
||
|
struct _pthread_queue *pqueue, pthread_descr_t thr)
|
||
|
{
|
||
|
pthread_descr_t prev;
|
||
|
pthread_descr_t tail;
|
||
|
if ((prev = (pthread_descr_t)((volatile void *)pqueue->tail)) != NULL)
|
||
|
{
|
||
|
tail = prev;
|
||
|
while (prev->p_nextwaiting != thr)
|
||
|
if ((prev = prev->p_nextwaiting) == tail)
|
||
|
{
|
||
|
prev = NULL;
|
||
|
break;
|
||
|
}
|
||
|
if (prev != NULL)
|
||
|
{
|
||
|
prev->p_nextwaiting = thr->p_nextwaiting;
|
||
|
if (tail == thr)
|
||
|
pqueue->tail = tail != prev ?
|
||
|
(_pthread_descr)((volatile void *)prev) : NULL;
|
||
|
thr->p_nextwaiting = NULL;
|
||
|
}
|
||
|
}
|
||
|
return (void *)prev;
|
||
|
}
|
||
|
|
||
|
PTHREAD_STATIC pthread_descr_t PTHREAD_FASTCALL pthread_queue_get(
|
||
|
struct _pthread_queue *pqueue)
|
||
|
{
|
||
|
pthread_descr_t thr;
|
||
|
pthread_descr_t tail;
|
||
|
do
|
||
|
{
|
||
|
thr = NULL;
|
||
|
if ((tail = (pthread_descr_t)((volatile void *)pqueue->tail)) == NULL)
|
||
|
break;
|
||
|
tail->p_nextwaiting = (thr = tail->p_nextwaiting)->p_nextwaiting;
|
||
|
if (thr == tail)
|
||
|
pqueue->tail = NULL;
|
||
|
thr->p_nextwaiting = NULL;
|
||
|
} while (thr->p_policy == PTHREAD_SCHEDPOL_TERMINATED);
|
||
|
return thr;
|
||
|
}
|
||
|
|
||
|
PTHREAD_STATIC void *PTHREAD_FASTCALL pthread_condsignal_inner(
|
||
|
pthread_cond_t *pcond)
|
||
|
{
|
||
|
pthread_mutex_t *pmutex;
|
||
|
pthread_descr_t thr;
|
||
|
pthread_descr_t thr2;
|
||
|
if ((thr = pthread_queue_get(&pcond->opaque_c_waiting)) != NULL)
|
||
|
{
|
||
|
pmutex = thr->p_condmutex;
|
||
|
thr->p_condmutex = NULL;
|
||
|
if ((thr2 = (pthread_descr_t)((volatile void *)pmutex->opaque_m_owner)) !=
|
||
|
NULL)
|
||
|
{
|
||
|
if (thr2 != thr)
|
||
|
pthread_queue_add(&pmutex->opaque_m_waiting, thr);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pmutex->opaque_m_owner = (_pthread_descr)((volatile void *)thr);
|
||
|
thr->p_mutexcount++;
|
||
|
pthread_sched_resume(thr);
|
||
|
}
|
||
|
}
|
||
|
return (void *)thr;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_create(pthread_t *ppthread,
|
||
|
const pthread_attr_t *pattr, void *(PTHREAD_USERCALL *rtn)(void *),
|
||
|
void *arg)
|
||
|
{
|
||
|
pthread_descr_t thr;
|
||
|
pthread_descr_t self;
|
||
|
void *stackbase;
|
||
|
size_t stacksize;
|
||
|
int res = EAGAIN;
|
||
|
int i;
|
||
|
if (!rtn)
|
||
|
ppthread = NULL;
|
||
|
pthread_noop_access(ppthread);
|
||
|
if (pattr == NULL || (stacksize = pattr->opaque_stacksize) == 0)
|
||
|
stacksize = (size_t)PTHREAD_STACK_DEFSIZE;
|
||
|
if (stacksize <= (size_t)PTHREAD_STACK_MINSIZE)
|
||
|
stacksize = (size_t)PTHREAD_STACK_MINSIZE;
|
||
|
stacksize = (stacksize / (sizeof(long) * 2)) * (sizeof(long) * 2);
|
||
|
if ((stackbase = PTHREAD_CORE_MALLOC(stacksize)) != NULL)
|
||
|
{
|
||
|
if ((thr = PTHREAD_CORE_MALLOC(((sizeof(struct pthread_descr_s) +
|
||
|
sizeof(int) - 1) / sizeof(int)) * sizeof(int))) != NULL)
|
||
|
{
|
||
|
i = ((sizeof(struct pthread_descr_s) - 1) / sizeof(int)) * sizeof(int);
|
||
|
do
|
||
|
{
|
||
|
*(volatile int *)((char *)thr + i) = 0;
|
||
|
} while ((i -= sizeof(int)) >= 0);
|
||
|
thr->p_suspended = 1;
|
||
|
thr->p_policy = SCHED_OTHER;
|
||
|
if (pattr != NULL)
|
||
|
{
|
||
|
thr->p_policy = pattr->opaque_schedpolicy;
|
||
|
thr->p_priority = pattr->opaque_schedparam.sched_priority;
|
||
|
if (pattr->opaque_detachstate == PTHREAD_CREATE_DETACHED)
|
||
|
thr->p_joining = thr;
|
||
|
}
|
||
|
thr->p_stackbase = stackbase;
|
||
|
thr->p_stacksize = stacksize;
|
||
|
thr->p_signum = -1;
|
||
|
thr->p_retval = arg;
|
||
|
thr->p_startrtn = (pthread_startrtn_t)rtn;
|
||
|
pthread_sched_disable();
|
||
|
pthread_descr_clearpending();
|
||
|
self = pthread_descr_self;
|
||
|
if (self->p_nextlive != self || !pthread_sched_init())
|
||
|
{
|
||
|
if (pattr != NULL && pattr->opaque_inheritsched == PTHREAD_INHERIT_SCHED)
|
||
|
{
|
||
|
thr->p_policy = self->p_policy;
|
||
|
thr->p_priority = self->p_priority;
|
||
|
}
|
||
|
thr->p_magic = PTHREAD_DESCR_MAGIC;
|
||
|
thr->p_prevlive = self;
|
||
|
(thr->p_nextlive = self->p_nextlive)->p_prevlive = thr;
|
||
|
self->p_nextlive = thr;
|
||
|
thr->p_suspended = 0;
|
||
|
*(volatile pthread_t *)ppthread = PTHREAD_DESCR_TID(thr);
|
||
|
res = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
PTHREAD_CORE_FREE(thr);
|
||
|
PTHREAD_CORE_FREE(stackbase);
|
||
|
}
|
||
|
pthread_sched_enable(0);
|
||
|
}
|
||
|
else PTHREAD_CORE_FREE(stackbase);
|
||
|
}
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API pthread_t PTHREAD_CALL pthread_self(void)
|
||
|
{
|
||
|
return PTHREAD_DESCR_TID(pthread_descr_self);
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_equal(pthread_t pthread,
|
||
|
pthread_t pthread2)
|
||
|
{
|
||
|
return pthread == pthread2;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API void PTHREAD_CALL pthread_exit(void *retval)
|
||
|
{
|
||
|
pthread_descr_t self;
|
||
|
pthread_descr_t thr;
|
||
|
pthread_keys_destroy();
|
||
|
pthread_sched_disable();
|
||
|
pthread_descr_clearpending();
|
||
|
(self = pthread_descr_self)->p_waketime.tv_sec = 0;
|
||
|
self->p_retval = retval;
|
||
|
self->p_policy = PTHREAD_SCHEDPOL_TERMINATED;
|
||
|
if ((thr = self->p_joining) != NULL)
|
||
|
{
|
||
|
if (thr != self)
|
||
|
pthread_sched_resume(thr);
|
||
|
else pthread_descr_pendremove = self;
|
||
|
}
|
||
|
pthread_sched_stopped = 1;
|
||
|
pthread_sched_enable(PTHREAD_SCHEDCMD_WAIT);
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_join(pthread_t pthread, void **pretval)
|
||
|
{
|
||
|
pthread_descr_t thr;
|
||
|
pthread_descr_t self;
|
||
|
int res = ESRCH;
|
||
|
if (pretval != NULL)
|
||
|
pthread_noop_access(pretval);
|
||
|
pthread_sched_disable();
|
||
|
pthread_descr_clearpending();
|
||
|
thr = PTHREAD_TID_DESCR(pthread);
|
||
|
self = thr;
|
||
|
if (PTHREAD_DESCR_VALID(thr))
|
||
|
{
|
||
|
res = EDEADLK;
|
||
|
if (pthread_sched_stopped == 1 && (self = pthread_descr_self) != thr)
|
||
|
{
|
||
|
if (thr->p_joining != NULL)
|
||
|
{
|
||
|
self = thr;
|
||
|
res = EINVAL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
thr->p_joining = self;
|
||
|
while (thr->p_policy != PTHREAD_SCHEDPOL_TERMINATED)
|
||
|
{
|
||
|
pthread_sched_enable(PTHREAD_SCHEDCMD_WAIT);
|
||
|
pthread_sched_disable();
|
||
|
}
|
||
|
if (pretval != NULL)
|
||
|
*pretval = thr->p_retval;
|
||
|
pthread_descr_destroy(thr);
|
||
|
res = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
pthread_sched_enable(0);
|
||
|
if (self != thr)
|
||
|
pthread_descr_free(thr);
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_detach(pthread_t pthread)
|
||
|
{
|
||
|
pthread_descr_t thr;
|
||
|
pthread_descr_t thr2;
|
||
|
int res = ESRCH;
|
||
|
pthread_sched_disable();
|
||
|
pthread_descr_clearpending();
|
||
|
thr = PTHREAD_TID_DESCR(pthread);
|
||
|
if (PTHREAD_DESCR_VALID(thr))
|
||
|
{
|
||
|
res = EINVAL;
|
||
|
if ((thr2 = thr->p_joining) != NULL)
|
||
|
{
|
||
|
if (thr2 != thr)
|
||
|
res = 0;
|
||
|
thr = NULL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
res = 0;
|
||
|
if (thr->p_policy != PTHREAD_SCHEDPOL_TERMINATED)
|
||
|
{
|
||
|
thr->p_joining = thr;
|
||
|
thr = NULL;
|
||
|
}
|
||
|
else pthread_descr_destroy(thr);
|
||
|
}
|
||
|
}
|
||
|
else thr = NULL;
|
||
|
pthread_sched_enable(0);
|
||
|
if (thr != NULL)
|
||
|
pthread_descr_free(thr);
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_attr_init(pthread_attr_t *pattr)
|
||
|
{
|
||
|
pattr->opaque_detachstate = PTHREAD_CREATE_JOINABLE;
|
||
|
pattr->opaque_schedpolicy = SCHED_OTHER;
|
||
|
pattr->opaque_schedparam.sched_priority = 0;
|
||
|
pattr->opaque_inheritsched = PTHREAD_EXPLICIT_SCHED;
|
||
|
pattr->opaque_scope = 0;
|
||
|
pattr->opaque_stackaddr = NULL;
|
||
|
pattr->opaque_stacksize = 0;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_attr_destroy(pthread_attr_t *pattr)
|
||
|
{
|
||
|
pthread_noop_access(pattr);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_attr_setdetachstate(
|
||
|
pthread_attr_t *pattr, int detachstate)
|
||
|
{
|
||
|
int res = EINVAL;
|
||
|
if (detachstate == PTHREAD_CREATE_JOINABLE ||
|
||
|
detachstate == PTHREAD_CREATE_DETACHED)
|
||
|
{
|
||
|
pattr->opaque_detachstate = detachstate;
|
||
|
res = 0;
|
||
|
}
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_attr_getdetachstate(
|
||
|
const pthread_attr_t *pattr, int *pdetachstate)
|
||
|
{
|
||
|
*pdetachstate = pattr->opaque_detachstate;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_attr_setschedparam(pthread_attr_t *pattr,
|
||
|
const struct sched_param *pparam)
|
||
|
{
|
||
|
int priority = pparam->sched_priority;
|
||
|
int policy = pattr->opaque_schedpolicy;
|
||
|
int res = EINVAL;
|
||
|
if (PTHREAD_SCHEDPRIO_MIN(policy) <= priority &&
|
||
|
PTHREAD_SCHEDPRIO_MAX(policy) >= priority)
|
||
|
{
|
||
|
pattr->opaque_schedparam.sched_priority = priority;
|
||
|
res = 0;
|
||
|
}
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_attr_getschedparam(
|
||
|
const pthread_attr_t *pattr, struct sched_param *pparam)
|
||
|
{
|
||
|
pparam->sched_priority = pattr->opaque_schedparam.sched_priority;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_attr_setschedpolicy(
|
||
|
pthread_attr_t *pattr, int policy)
|
||
|
{
|
||
|
int res = EINVAL;
|
||
|
if (policy == SCHED_OTHER || policy == SCHED_FIFO || policy == SCHED_RR)
|
||
|
{
|
||
|
pattr->opaque_schedpolicy = policy;
|
||
|
res = 0;
|
||
|
}
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_attr_getschedpolicy(
|
||
|
const pthread_attr_t *pattr, int *ppolicy)
|
||
|
{
|
||
|
*ppolicy = pattr->opaque_schedpolicy;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_attr_setinheritsched(
|
||
|
pthread_attr_t *pattr, int inherit)
|
||
|
{
|
||
|
int res = EINVAL;
|
||
|
if (inherit == PTHREAD_INHERIT_SCHED || inherit == PTHREAD_EXPLICIT_SCHED)
|
||
|
{
|
||
|
pattr->opaque_inheritsched = inherit;
|
||
|
res = 0;
|
||
|
}
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_attr_getinheritsched(
|
||
|
const pthread_attr_t *pattr, int *pinherit)
|
||
|
{
|
||
|
*pinherit = pattr->opaque_inheritsched;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_attr_setstacksize(pthread_attr_t *pattr,
|
||
|
size_t stacksize)
|
||
|
{
|
||
|
pattr->opaque_stacksize = stacksize;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_attr_getstacksize(
|
||
|
const pthread_attr_t *pattr, size_t *pstacksize)
|
||
|
{
|
||
|
*pstacksize = pattr->opaque_stacksize;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_setschedparam(pthread_t pthread,
|
||
|
int policy, const struct sched_param *pparam)
|
||
|
{
|
||
|
int res = ESRCH;
|
||
|
int priority = pparam->sched_priority;
|
||
|
pthread_descr_t thr;
|
||
|
pthread_sched_disable();
|
||
|
thr = PTHREAD_TID_DESCR(pthread);
|
||
|
if (PTHREAD_DESCR_VALID(thr) && thr->p_policy != PTHREAD_SCHEDPOL_TERMINATED)
|
||
|
{
|
||
|
res = EINVAL;
|
||
|
if ((policy == SCHED_OTHER || policy == SCHED_FIFO || policy == SCHED_RR) &&
|
||
|
PTHREAD_SCHEDPRIO_MIN(policy) <= priority &&
|
||
|
PTHREAD_SCHEDPRIO_MAX(policy) >= priority)
|
||
|
{
|
||
|
thr->p_policy = policy;
|
||
|
thr->p_priority = priority;
|
||
|
res = 0;
|
||
|
}
|
||
|
}
|
||
|
pthread_sched_enable(0);
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_getschedparam(pthread_t pthread,
|
||
|
int *ppolicy, struct sched_param *pparam)
|
||
|
{
|
||
|
int res = ESRCH;
|
||
|
int policy;
|
||
|
pthread_descr_t thr;
|
||
|
pthread_noop_access(ppolicy);
|
||
|
pthread_noop_access(pparam);
|
||
|
pthread_sched_disable();
|
||
|
thr = PTHREAD_TID_DESCR(pthread);
|
||
|
if (PTHREAD_DESCR_VALID(thr) &&
|
||
|
(policy = thr->p_policy) != PTHREAD_SCHEDPOL_TERMINATED)
|
||
|
{
|
||
|
*ppolicy = policy;
|
||
|
pparam->sched_priority = thr->p_priority;
|
||
|
res = 0;
|
||
|
}
|
||
|
pthread_sched_enable(0);
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_mutex_init(pthread_mutex_t *pmutex,
|
||
|
const pthread_mutexattr_t *pmutexattr)
|
||
|
{
|
||
|
pmutex->opaque_m_spinlock = 0;
|
||
|
pmutex->opaque_m_count = 0;
|
||
|
pmutex->opaque_m_owner = NULL;
|
||
|
pmutex->opaque_m_kind = pmutexattr != NULL ? pmutexattr->opaque_mutexkind :
|
||
|
PTHREAD_MUTEX_FAST_NP;
|
||
|
pmutex->opaque_m_waiting.head = NULL;
|
||
|
pmutex->opaque_m_waiting.tail = NULL;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_mutex_destroy(pthread_mutex_t *pmutex)
|
||
|
{
|
||
|
return pmutex->opaque_m_owner != NULL ? EBUSY : 0;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_mutex_trylock(pthread_mutex_t *pmutex)
|
||
|
{
|
||
|
int res = EBUSY;
|
||
|
if (pmutex->opaque_m_owner == NULL)
|
||
|
{
|
||
|
pthread_sched_disable();
|
||
|
if (*(volatile _pthread_descr *)(&pmutex->opaque_m_owner) == NULL)
|
||
|
{
|
||
|
((pthread_descr_t)((volatile void *)(pmutex->opaque_m_owner =
|
||
|
(_pthread_descr)((volatile void *)pthread_descr_self))))->p_mutexcount++;
|
||
|
res = 0;
|
||
|
}
|
||
|
pthread_sched_stopped--;
|
||
|
}
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_mutex_lock(pthread_mutex_t *pmutex)
|
||
|
{
|
||
|
pthread_descr_t self;
|
||
|
pthread_descr_t thr;
|
||
|
int res;
|
||
|
pthread_noop_access(pmutex);
|
||
|
pthread_sched_disable();
|
||
|
self = pthread_descr_self;
|
||
|
if ((thr = (pthread_descr_t)((volatile void *)pmutex->opaque_m_owner)) !=
|
||
|
NULL)
|
||
|
{
|
||
|
res = EDEADLK;
|
||
|
if (thr != self && pthread_sched_stopped == 1 &&
|
||
|
thr->p_policy != PTHREAD_SCHEDPOL_TERMINATED &&
|
||
|
self->p_nextwaiting == NULL)
|
||
|
{
|
||
|
pthread_queue_add(&pmutex->opaque_m_waiting, self);
|
||
|
do
|
||
|
{
|
||
|
pthread_sched_enable(PTHREAD_SCHEDCMD_WAIT);
|
||
|
pthread_sched_disable();
|
||
|
} while ((pthread_descr_t)((volatile void *)pmutex->opaque_m_owner) !=
|
||
|
self);
|
||
|
res = 0;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pmutex->opaque_m_owner = (_pthread_descr)((volatile void *)self);
|
||
|
self->p_mutexcount++;
|
||
|
res = 0;
|
||
|
}
|
||
|
pthread_sched_stopped--;
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_mutex_unlock(pthread_mutex_t *pmutex)
|
||
|
{
|
||
|
pthread_descr_t thr;
|
||
|
pthread_descr_t self;
|
||
|
int res = EPERM;
|
||
|
pthread_noop_access(pmutex);
|
||
|
pthread_sched_disable();
|
||
|
if ((self = pthread_descr_self) ==
|
||
|
(pthread_descr_t)((volatile void *)pmutex->opaque_m_owner))
|
||
|
{
|
||
|
self->p_mutexcount--;
|
||
|
thr = pthread_queue_get(&pmutex->opaque_m_waiting);
|
||
|
if ((pmutex->opaque_m_owner = (_pthread_descr)((volatile void *)thr)) !=
|
||
|
NULL)
|
||
|
{
|
||
|
thr->p_mutexcount++;
|
||
|
pthread_sched_resume(thr);
|
||
|
}
|
||
|
res = 0;
|
||
|
}
|
||
|
pthread_sched_enable(0);
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_mutexattr_init(
|
||
|
pthread_mutexattr_t *pmutexattr)
|
||
|
{
|
||
|
pmutexattr->opaque_mutexkind = PTHREAD_MUTEX_FAST_NP;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_mutexattr_destroy(
|
||
|
pthread_mutexattr_t *pmutexattr)
|
||
|
{
|
||
|
pthread_noop_access(pmutexattr);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_cond_init(pthread_cond_t *pcond,
|
||
|
const pthread_condattr_t *pcondattr)
|
||
|
{
|
||
|
if (pcondattr != NULL)
|
||
|
pthread_noop_access(*(pthread_condattr_t **)&pcondattr);
|
||
|
pcond->opaque_c_spinlock = 0;
|
||
|
pcond->opaque_c_waiting.head = NULL;
|
||
|
pcond->opaque_c_waiting.tail = NULL;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_cond_destroy(pthread_cond_t *pcond)
|
||
|
{
|
||
|
return pcond->opaque_c_waiting.tail != NULL ? EBUSY : 0;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_cond_signal(pthread_cond_t *pcond)
|
||
|
{
|
||
|
pthread_noop_access(pcond);
|
||
|
pthread_sched_disable();
|
||
|
(void)pthread_condsignal_inner(pcond);
|
||
|
pthread_sched_stopped--;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_cond_broadcast(pthread_cond_t *pcond)
|
||
|
{
|
||
|
pthread_noop_access(pcond);
|
||
|
pthread_sched_disable();
|
||
|
for (;;)
|
||
|
{
|
||
|
if (pthread_condsignal_inner(pcond) == NULL)
|
||
|
break;
|
||
|
}
|
||
|
pthread_sched_enable(0);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_cond_wait(pthread_cond_t *pcond,
|
||
|
pthread_mutex_t *pmutex)
|
||
|
{
|
||
|
pthread_descr_t self;
|
||
|
pthread_descr_t thr;
|
||
|
int res = EPERM;
|
||
|
pthread_noop_access(pcond);
|
||
|
pthread_noop_access(pmutex);
|
||
|
pthread_sched_disable();
|
||
|
if ((self = pthread_descr_self) ==
|
||
|
(pthread_descr_t)((volatile void *)pmutex->opaque_m_owner))
|
||
|
{
|
||
|
res = EDEADLK;
|
||
|
if (pthread_sched_stopped == 1 && self->p_nextwaiting == NULL)
|
||
|
{
|
||
|
self->p_condmutex = pmutex;
|
||
|
pthread_queue_add(&pcond->opaque_c_waiting, self);
|
||
|
self->p_mutexcount--;
|
||
|
thr = pthread_queue_get(&pmutex->opaque_m_waiting);
|
||
|
if ((pmutex->opaque_m_owner = (_pthread_descr)((volatile void *)thr)) !=
|
||
|
NULL)
|
||
|
{
|
||
|
thr->p_mutexcount++;
|
||
|
pthread_sched_resume(thr);
|
||
|
}
|
||
|
do
|
||
|
{
|
||
|
pthread_sched_enable(PTHREAD_SCHEDCMD_WAIT);
|
||
|
pthread_sched_disable();
|
||
|
} while ((pthread_descr_t)((volatile void *)pmutex->opaque_m_owner) !=
|
||
|
self);
|
||
|
res = 0;
|
||
|
}
|
||
|
}
|
||
|
pthread_sched_stopped--;
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_cond_timedwait(pthread_cond_t *pcond,
|
||
|
pthread_mutex_t *pmutex, const struct timespec *pabstime)
|
||
|
{
|
||
|
pthread_descr_t self;
|
||
|
pthread_descr_t thr;
|
||
|
struct timespec ts;
|
||
|
struct timespec ts2;
|
||
|
PTHREAD_CURTIME_T tv;
|
||
|
int res = EPERM;
|
||
|
pthread_noop_access(pcond);
|
||
|
pthread_noop_access(pmutex);
|
||
|
ts.tv_sec = pabstime->tv_sec;
|
||
|
ts.tv_nsec = pabstime->tv_nsec;
|
||
|
PTHREAD_CURTIME_GET(&tv, &ts2);
|
||
|
pthread_sched_disable();
|
||
|
if ((self = pthread_descr_self) ==
|
||
|
(pthread_descr_t)((volatile void *)pmutex->opaque_m_owner))
|
||
|
{
|
||
|
res = EDEADLK;
|
||
|
if (self->p_nextwaiting == NULL)
|
||
|
{
|
||
|
res = ETIMEDOUT;
|
||
|
if ((long)ts.tv_sec - (long)ts2.tv_sec > 0 ||
|
||
|
(ts.tv_sec == ts2.tv_sec && ts.tv_nsec > ts2.tv_nsec))
|
||
|
{
|
||
|
self->p_condmutex = pmutex;
|
||
|
pthread_queue_add(&pcond->opaque_c_waiting, self);
|
||
|
self->p_mutexcount--;
|
||
|
thr = pthread_queue_get(&pmutex->opaque_m_waiting);
|
||
|
if ((pmutex->opaque_m_owner = (_pthread_descr)((volatile void *)thr)) !=
|
||
|
NULL)
|
||
|
{
|
||
|
thr->p_mutexcount++;
|
||
|
pthread_sched_resume(thr);
|
||
|
}
|
||
|
if ((self->p_waketime.tv_sec = ts.tv_sec) == 0)
|
||
|
self->p_waketime.tv_sec = (time_t)-1;
|
||
|
self->p_waketime.tv_nsec = ts.tv_nsec;
|
||
|
pthread_sched_enable(PTHREAD_SCHEDCMD_WAIT);
|
||
|
pthread_sched_disable();
|
||
|
res = 0;
|
||
|
if ((pthread_descr_t)((volatile void *)pmutex->opaque_m_owner) != self)
|
||
|
{
|
||
|
if (pthread_queue_remove(&pcond->opaque_c_waiting, self) != NULL)
|
||
|
{
|
||
|
self->p_condmutex = NULL;
|
||
|
res = self->p_waketime.tv_sec ? EINTR : ETIMEDOUT;
|
||
|
if (pmutex->opaque_m_owner != NULL)
|
||
|
pthread_queue_add(&pmutex->opaque_m_waiting, self);
|
||
|
else
|
||
|
{
|
||
|
pmutex->opaque_m_owner = (_pthread_descr)((volatile void *)self);
|
||
|
self->p_mutexcount++;
|
||
|
}
|
||
|
}
|
||
|
while ((pthread_descr_t)((volatile void *)pmutex->opaque_m_owner) !=
|
||
|
self)
|
||
|
{
|
||
|
pthread_sched_enable(PTHREAD_SCHEDCMD_WAIT);
|
||
|
pthread_sched_disable();
|
||
|
}
|
||
|
}
|
||
|
self->p_waketime.tv_sec = 0;
|
||
|
self->p_waketime.tv_nsec = 0;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
pthread_sched_stopped--;
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_condattr_init(
|
||
|
pthread_condattr_t *pcondattr)
|
||
|
{
|
||
|
pcondattr->opaque_condflags = 0;
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_condattr_destroy(
|
||
|
pthread_condattr_t *pcondattr)
|
||
|
{
|
||
|
pthread_noop_access(pcondattr);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_key_create(pthread_key_t *pkey,
|
||
|
void (PTHREAD_USERCALL *destr_rtn)(void *))
|
||
|
{
|
||
|
unsigned i;
|
||
|
pthread_noop_access(pkey);
|
||
|
pthread_sched_disable();
|
||
|
for (i = 0; i < PTHREAD_KEYS_MAX; i++)
|
||
|
if (!pthread_keys_destr[i])
|
||
|
{
|
||
|
pthread_keys_destr[i] = destr_rtn ? (pthread_destr_t)destr_rtn :
|
||
|
(pthread_destr_t)-1L;
|
||
|
*pkey = (pthread_key_t)i;
|
||
|
break;
|
||
|
}
|
||
|
pthread_sched_enable(0);
|
||
|
return i < PTHREAD_KEYS_MAX ? 0 : EAGAIN;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_key_delete(pthread_key_t key)
|
||
|
{
|
||
|
pthread_descr_t thr;
|
||
|
pthread_descr_t self;
|
||
|
int res = EINVAL;
|
||
|
pthread_sched_disable();
|
||
|
if ((unsigned)key < PTHREAD_KEYS_MAX &&
|
||
|
pthread_keys_destr[(unsigned)key] != (pthread_destr_t)0)
|
||
|
{
|
||
|
self = pthread_descr_self;
|
||
|
pthread_keys_destr[(unsigned)key] = (pthread_destr_t)0;
|
||
|
thr = self;
|
||
|
do
|
||
|
{
|
||
|
thr->p_specific[(unsigned)key] = NULL;
|
||
|
} while ((thr = thr->p_prevlive) != self);
|
||
|
res = 0;
|
||
|
}
|
||
|
pthread_sched_enable(0);
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_setspecific(pthread_key_t key,
|
||
|
const void *val)
|
||
|
{
|
||
|
int res = EINVAL;
|
||
|
if ((unsigned)key < PTHREAD_KEYS_MAX &&
|
||
|
pthread_keys_destr[(unsigned)key] != (pthread_destr_t)0)
|
||
|
{
|
||
|
pthread_descr_self->p_specific[(unsigned)key] = (void *)val;
|
||
|
res = 0;
|
||
|
}
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API void *PTHREAD_CALL pthread_getspecific(pthread_key_t key)
|
||
|
{
|
||
|
return (unsigned)key < PTHREAD_KEYS_MAX ?
|
||
|
pthread_descr_self->p_specific[(unsigned)key] : NULL;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL pthread_kill(pthread_t pthread, int signum)
|
||
|
{
|
||
|
pthread_descr_t thr;
|
||
|
int res;
|
||
|
int p_errno = errno;
|
||
|
PTHREAD_SIGRAISE_T oact;
|
||
|
if (PTHREAD_DESCR_TID(pthread_descr_self) != pthread)
|
||
|
{
|
||
|
res = EINVAL;
|
||
|
if (PTHREAD_SIG_VALID(signum))
|
||
|
{
|
||
|
res = ESRCH;
|
||
|
pthread_sched_disable();
|
||
|
thr = PTHREAD_TID_DESCR(pthread);
|
||
|
while (PTHREAD_DESCR_VALID(thr) &&
|
||
|
thr->p_policy != PTHREAD_SCHEDPOL_TERMINATED)
|
||
|
{
|
||
|
if ((p_errno = thr->p_signum) == signum || p_errno == -1)
|
||
|
{
|
||
|
thr->p_signum = signum;
|
||
|
pthread_sched_resume(thr);
|
||
|
res = 0;
|
||
|
break;
|
||
|
}
|
||
|
pthread_sched_enable(PTHREAD_SCHEDCMD_YIELD);
|
||
|
pthread_sched_disable();
|
||
|
}
|
||
|
pthread_sched_enable(0);
|
||
|
}
|
||
|
else PTHREAD_ERRNO_SET(p_errno);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
res = 0;
|
||
|
if (PTHREAD_SIG_RAISE(signum, &oact))
|
||
|
{
|
||
|
PTHREAD_ERRNO_SET(p_errno);
|
||
|
res = EINVAL;
|
||
|
}
|
||
|
}
|
||
|
return res;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API void PTHREAD_CALL pthread_resume_all_np(void)
|
||
|
{
|
||
|
if (pthread_sched_stopped)
|
||
|
pthread_sched_stopped--;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API void PTHREAD_CALL pthread_suspend_all_np(void)
|
||
|
{
|
||
|
pthread_sched_disable();
|
||
|
}
|
||
|
|
||
|
PTHREAD_API unsigned PTHREAD_CALL pthread_usleep_np(unsigned usec)
|
||
|
{
|
||
|
pthread_descr_t self;
|
||
|
struct timespec ts;
|
||
|
struct timespec ts2;
|
||
|
PTHREAD_CURTIME_T tv;
|
||
|
long diff;
|
||
|
PTHREAD_CURTIME_GET(&tv, &ts);
|
||
|
ts.tv_sec += (time_t)((unsigned long)usec / (unsigned long)(1000L * 1000L));
|
||
|
if ((unsigned long)(ts.tv_nsec += (long)((unsigned long)usec %
|
||
|
(unsigned long)(1000L * 1000L)) * 1000L) >=
|
||
|
(unsigned long)(1000L * 1000L * 1000L))
|
||
|
{
|
||
|
ts.tv_sec++;
|
||
|
ts.tv_nsec -= 1000L * 1000L * 1000L;
|
||
|
}
|
||
|
pthread_sched_disable();
|
||
|
self = pthread_descr_self;
|
||
|
if ((self->p_waketime.tv_sec = ts.tv_sec) == 0)
|
||
|
self->p_waketime.tv_sec = (time_t)-1;
|
||
|
self->p_waketime.tv_nsec = ts.tv_nsec;
|
||
|
pthread_sched_enable(PTHREAD_SCHEDCMD_WAIT);
|
||
|
self->p_waketime.tv_sec = 0;
|
||
|
self->p_waketime.tv_nsec = 0;
|
||
|
PTHREAD_CURTIME_GET(&tv, &ts2);
|
||
|
usec = 0;
|
||
|
if (((diff = (long)ts.tv_sec - (long)ts2.tv_sec) > 0 ||
|
||
|
(!diff && ts.tv_nsec > ts2.tv_nsec)) &&
|
||
|
(usec = (unsigned)(diff * (1000L * 1000L) +
|
||
|
((long)ts.tv_nsec - (long)ts2.tv_nsec) / 1000L)) != 0)
|
||
|
PTHREAD_ERRNO_SET(EINTR);
|
||
|
return usec;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL sched_yield(void)
|
||
|
{
|
||
|
pthread_sched_disable();
|
||
|
pthread_sched_enable(PTHREAD_SCHEDCMD_YIELD);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL sched_get_priority_max(int policy)
|
||
|
{
|
||
|
if (policy != SCHED_OTHER && policy != SCHED_FIFO && policy != SCHED_RR)
|
||
|
{
|
||
|
PTHREAD_ERRNO_SET(EINVAL);
|
||
|
return -1;
|
||
|
}
|
||
|
return PTHREAD_SCHEDPRIO_MAX(policy);
|
||
|
}
|
||
|
|
||
|
PTHREAD_API int PTHREAD_CALL sched_get_priority_min(int policy)
|
||
|
{
|
||
|
if (policy != SCHED_OTHER && policy != SCHED_FIFO && policy != SCHED_RR)
|
||
|
{
|
||
|
PTHREAD_ERRNO_SET(EINVAL);
|
||
|
return -1;
|
||
|
}
|
||
|
return PTHREAD_SCHEDPRIO_MIN(policy);
|
||
|
}
|