/*
 *  pthread.h	Thread definitions
 *
 *  Copyright (C) by Quantum Software Systems 1995-1996. All rights reserved.
 */
#ifndef _PTHREAD_H_INCLUDED
#define _PTHREAD_H_INCLUDED

#define _QNX_C_SOURCE 425

#ifndef __TIME_H_INCLUDED
 #include <time.h>
#endif

#ifndef _ERRNO_H_INCLUDED
 #include <errno.h>
#endif

#ifndef _SCHED_H_INCLUDED
 #include <sys/sched.h>
#endif

#ifndef _SIGNAL_H_INCLUDED
 #include <signal.h>
#endif

#include <unistd.h>
#include <limits.h>

#ifndef __NEUTRINO_H_INCLUDED
 #include "qnx.h"
#endif

#if __WATCOMC__ > 1000
#pragma pack(push,1);
#else
#pragma pack(1);
#endif

#ifdef __cplusplus
extern "C" {
#endif

typedef struct _thread_attr pthread_attr_t; 

#define PTHREAD_DETACHSTATE_MASK		0x01
#define PTHREAD_CREATE_JOINABLE				0x00
#define PTHREAD_CREATE_DETACHED				0x01

#define PTHREAD_INHERITSCHED_MASK		0x02
#define PTHREAD_INHERIT_SCHED				0x00
#define PTHREAD_EXPLICIT_SCHED				0x02

#define PTHREAD_CONTENTIONSCOPE_MASK	0x04
#define PTHREAD_SCOPE_SYSTEM				0x00
#define PTHREAD_SCOPE_PROCESS				0x04	/* Not supported */

#define PTHREAD_MULTISIG_MASK			0x08
#define PTHREAD_MULTISIG_ALLOW				0x00
#define PTHREAD_MULTISIG_DISALLOW			0x08

#define PTHREAD_CSTATE_MASK				0x10
#define PTHREAD_CANCEL_ENABLE				0x00
#define PTHREAD_CANCEL_DISABLE				0x10

#define PTHREAD_CTYPE_MASK				0x20
#define PTHREAD_CANCEL_DEFERRED				0x00
#define PTHREAD_CANCEL_ASYNCHRONOUS			0x20

#define PTHREAD_CANCEL_PENDING			0x40

#define PTHREAD_CANCELLED ((void *)-1)
#define PTHREAD_CANCELED ((void *)-1)

typedef pid_t pthread_t;

typedef int pthread_key_t;

#define PTHREAD_PRIO_INHERIT	0
#define PTHREAD_PRIO_NONE		1
#define PTHREAD_PRIO_PROTECT	2

/* thread attribute prototypes */
extern const pthread_attr_t pthread_attr_default;
extern int pthread_attr_init(pthread_attr_t *attr);
extern int pthread_attr_destroy(pthread_attr_t *attr);
extern int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize);
extern int pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize);
extern int pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr);
extern int pthread_attr_getstackaddr(const pthread_attr_t *addr, void **stackaddr);
extern int pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate);
extern int pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate);

/* scheduling related functions */
extern int pthread_attr_setscope(pthread_attr_t *attr, int contentionscope);
extern int pthread_attr_getscope(const pthread_attr_t *attr, int *contentionscope);
extern int pthread_attr_setinheritsched(pthread_attr_t *attr, int inheritsched);
extern int pthread_attr_getinheritsched(const pthread_attr_t *attr, int *inheritsched);
extern int pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy);
extern int pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy);
extern int pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param);
extern int pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param);

/* thread creation prototypes */
extern int pthread_create(pthread_t *thread, const pthread_attr_t *attr, 
	void *(*start_routine)(void *), void *arg);
extern int pthread_join(pthread_t thread, void **value_ptr);
extern int pthread_detach(pthread_t thread);

extern int pthread_cancel(pthread_t thread);
extern int pthread_setcancelstate(int state, int *oldstate);
extern int pthread_setcanceltype(int type, int *oldtype);
extern void pthread_exit(void *value_ptr);
extern pthread_t pthread_self(void);
extern int pthread_equal(pthread_t t1, pthread_t t2);
#ifdef __INLINE_FUNCTIONS__
#define pthread_self()				(_TLS)
#define pthread_equal( _t1, _t2 )	((_t1) == (_t2))
#endif

/* dynamic thread scheduling parameters */
extern int pthread_getschedparam(const pthread_t thread, int *policy, struct sched_param *param);
extern int pthread_setschedparam(pthread_t thread, int policy, const struct sched_param *param);

extern void pthread_testcancel(void);
#ifdef __INLINE_FUNCTIONS__
#define pthread_testcancel() if((_TLS->flags & (PTHREAD_CSTATE_MASK|PTHREAD_CANCEL_PENDING)) == \
				(PTHREAD_CANCEL_ENABLE|PTHREAD_CANCEL_PENDING)) pthread_exit(PTHREAD_CANCELLED);
#endif


/* thread cancellation handlers */

typedef struct _pthread_cleanup_handler {
    struct _pthread_cleanup_handler *next;
    void (*routine)(void *arg);
    void *arg;
} _pthread_cleanup_handler_t;

#define pthread_cleanup_push(_func, _arg) \
	{ \
	struct _pthread_cleanup_handler __cleanup_handler; \
	__cleanup_handler.routine = (_func); \
	__cleanup_handler.arg = (_arg); \
	__cleanup_handler.next = ( _pthread_cleanup_handler_t * ) _TLS->cleanup; \
	_TLS->cleanup = &__cleanup_handler;

#define pthread_cleanup_pop(_ex) \
	_TLS->cleanup = __cleanup_handler.next; \
	((_ex)?(*__cleanup_handler.routine)(__cleanup_handler.arg):(void)0);\
	}

/* pthread_key prototypes */
extern int pthread_key_create(pthread_key_t *key, void (*destructor)(void *));
extern int pthread_key_delete(pthread_key_t key);
extern int pthread_setspecific(pthread_key_t key, const void *value);
extern void *pthread_getspecific(pthread_key_t key);
#ifdef __INLINE_FUNCTIONS__
#define pthread_getspecific(key)	((key) < _TLS->numkeys ? _TLS->keydata[key] : 0)
#endif


/* pthread synchronization prototypes */
#define PTHREAD_MUTEX_INITIALIZER	{ _NTO_SYNC_NONRECURSIVE, -1 }
#define PTHREAD_RMUTEX_INITIALIZER	{ 0, -1 }
#define PTHREAD_COND_INITIALIZER	{ 0, -1 }

#define PTHREAD_PROCESSSHARED_MASK			0x01
#define PTHREAD_PROCESS_PRIVATE				0x00
#define PTHREAD_PROCESS_SHARED				0x01

#define PTHREAD_RECURSIVE_MASK				0x02
#define PTHREAD_RECURSIVE_DISABLE			0x00
#define PTHREAD_RECURSIVE_ENABLE			0x02

typedef sync_attr_t pthread_mutexattr_t;
typedef sync_attr_t pthread_condattr_t;

typedef sync_t pthread_mutex_t;
typedef sync_t pthread_cond_t;

/* synchronization stuff */
extern int pthread_mutexattr_init(pthread_mutexattr_t *attr);
extern int pthread_mutexattr_destroy(pthread_mutexattr_t *attr);

/* We always allow process shared */
extern int pthread_mutexattr_getpshared(const pthread_mutexattr_t *attr, int *pshared);
extern int pthread_mutexattr_setpshared(pthread_mutexattr_t *attr,int pshared);

/* synchronization scheduling */
extern int pthread_mutexattr_setprotocol(pthread_mutexattr_t *attr, int protocol);
extern int pthread_mutexattr_getprotocol(const pthread_mutexattr_t *attr, int *protocol);
extern int pthread_mutexattr_setprioceiling(pthread_mutexattr_t *attr, int prioceiling);
extern int pthread_mutexattr_getprioceiling(const pthread_mutexattr_t *attr, int *prioceiling);

/* mutex recursion */
extern int pthread_mutexattr_setrecursive(const pthread_mutexattr_t *attr, int recursive);
extern int pthread_mutexattr_getrecursive(const pthread_mutexattr_t *attr, int *recursive);

extern int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
extern int pthread_mutex_destroy(pthread_mutex_t *mutex);
extern int pthread_mutex_lock( pthread_mutex_t *mutex );
extern int pthread_mutex_trylock( pthread_mutex_t *mutex );
extern int pthread_mutex_unlock( pthread_mutex_t *mutex );
extern int pthread_mutex_timedlock( pthread_mutex_t *mutex, const struct timespec *abstime);

/* dynamically change the priority ceiling of a mutex */
extern int pthread_mutex_setprioceiling(pthread_mutex_t *mutex, int prioceiling, int *old_ceiling);
extern int pthread_mutex_getprioceiling(const pthread_mutex_t *mutex, int *prioceiling);

extern int pthread_condattr_init( pthread_condattr_t *attr );
extern int pthread_condattr_destroy( pthread_condattr_t *attr );

/* Next two functions are not supported currently */
extern int pthread_condattr_getpshared(const pthread_condattr_t *attr, int *pshared );
extern int pthread_condattr_setpshared( pthread_condattr_t *attr, int pshared );

extern int pthread_cond_init( pthread_cond_t *cond, pthread_condattr_t *attr );
extern int pthread_cond_destroy( pthread_cond_t *cond );
extern int pthread_cond_signal( pthread_cond_t *cond );
extern int pthread_cond_broadcast( pthread_cond_t *cond );
extern int pthread_cond_wait( pthread_cond_t *cond, pthread_mutex_t *mutex );
extern int pthread_cond_timedwait( pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime);

extern int __cmpxchg(int *dst, int src);
extern int __xchg(int *dst, int src);

#ifdef __386__
#pragma aux __cmpxchg = ".486" "xor eax,eax" "lock cmpxchg 0[edx],ebx" parm [edx] [ebx] modify exact [eax] value [eax];
#pragma aux __xchg = "xchg 0[edx],eax" parm [edx] [eax] modify exact [eax] value [eax];
#endif

#define _mutex_lock(_m)		(__cmpxchg(&(_m)->owner, _TLS->owner) ? SyncWait_r(_m) : EOK)
#define _mutex_trylock(_m)	(__cmpxchg(&(_m)->owner, _TLS->owner) ? EBUSY : EOK)
#define _mutex_unlock(_m)	((__xchg(&(_m)->owner, 0) & _NTO_SYNC_WAITING) ? SyncWakeup_r((_m), 0) : EOK)

/* sleepon */
extern int pthread_sleepon_lock(void);
extern int pthread_sleepon_wait(void *addr);
extern int pthread_sleepon_signal(void *addr);
extern int pthread_sleepon_broadcast(void *addr);
extern int pthread_sleepon_unlock(void);

extern int qnx_sync_info(sync_t *sync, struct _sync_info *info);

/* pthread_once prototypes */
typedef struct {
	int					once;
	pthread_mutex_t		mutex;
} pthread_once_t;

#define PTHREAD_ONCE_INIT { 0, PTHREAD_MUTEX_INITIALIZER }

extern int pthread_once(pthread_once_t *once_control, void (*init_routine)(void));
#ifdef __INLINE_FUNCTIONS__
extern int __pthread_once(pthread_once_t *once_control, void (*init_routine)(void));
#define pthread_once(_c, _f)	((_c)->once ? 0 : __pthread_once((_c),(_f)) )
#endif


/* reader/writer locks */
#define PTHREAD_RWLOCK_INITIALIZER	{ 0, 0, 0, 0, 0, PTHREAD_MUTEX_INITIALIZER, \
	PTHREAD_COND_INITIALIZER, PTHREAD_COND_INITIALIZER }

typedef struct {
	void* spare;
} pthread_rwlockattr_t;

int pthread_rwlockattr_init(pthread_rwlockattr_t*);
int pthread_rwlockattr_destroy(pthread_rwlockattr_t*);

typedef struct {
	int active;				/* -1 = writer else # of active readers */
	void* spare;
	int blockedwriters;		/* # of waiting readers */
	int blockedreaders;		/* # of waiting writers */
	int heavy;				/* the rwlock is under heavy contention */
	pthread_mutex_t lock;	/* the controlling mutex */
	pthread_cond_t rcond;	/* condition variable for readers */
	pthread_cond_t wcond;	/* condition variable for writers */
} pthread_rwlock_t;

extern int __pthread_rwlock_shared(pthread_rwlock_t*, int preventblock);
extern int __pthread_rwlock_exclusive(pthread_rwlock_t*, int preventblock);

extern int pthread_rwlock_init(pthread_rwlock_t *, const pthread_rwlockattr_t*);
extern int pthread_rwlock_destroy(pthread_rwlock_t *);
extern int pthread_rwlock_shared(pthread_rwlock_t*);
#define pthread_rwlock_shared(x)  __pthread_rwlock_shared(x, 0)
extern int pthread_rwlock_exclusive(pthread_rwlock_t*);
#define pthread_rwlock_exclusive(x)  __pthread_rwlock_exclusive(x, 0)
extern int pthread_rwlock_unlock(pthread_rwlock_t*);
extern int pthread_rwlock_tryshared(pthread_rwlock_t*);
#define pthread_rwlock_tryshared(x)  __pthread_rwlock_shared(x, 1)
extern int pthread_rwlock_tryexclusive(pthread_rwlock_t*);
#define pthread_rwlock_tryexclusive(x)  __pthread_rwlock_exclusive(x, 1)


/* signals */
extern int pthread_kill(pthread_t thread, int sig);
extern int pthread_sigmask(int how, const sigset_t *set, sigset_t *oset);

extern int pthread_atfork(void (*prepare)(void), void (*parent)(void), void (*child)(void));

#ifdef __cplusplus
};
#endif

#if __WATCOMC__ > 1000
#pragma pack(pop);
#else
#pragma pack();
#endif

#endif
