/*
 * Copyright (c) 2006-2007 MIPS Technologies, Inc.
 * 
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 
 *      * Redistributions of source code must retain the above copyright
 *        notice, this list of conditions and the following disclaimer.
 *      * Redistributions in binary form must reproduce the above
 *      copyright
 *        notice, this list of conditions and the following disclaimer
 *        in the documentation and/or other materials provided with
 *        the distribution.
 *      * Neither the name of MIPS Technologies Inc. nor the names of its
 *        contributors may be used to endorse or promote products derived
 *        from this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

/*
 * sdethread.h: generic thread interface for SDE library
 */


#ifndef __SDETHREAD_H
#define __SDETHREAD_H

#include <sys/types.h>

#ifdef __cplusplus
extern "C" {
#endif

/*
   THREAD CONTROL 
  
   A pointer to the thread structure, only used as a unique thread
   identifier.  */
typedef void * __sdethread_t;
/* A function which returns the unique thread ID.  */
__sdethread_t __sdethread_self (void);

/*
 * MUTEXES
 *
 * Mutexes do not need to be "recursive" (i.e. counting) type, however
 * if possible they should use a priority inheritance protocol to
 * prevent priority inversion being caused by the C library.
 */

/* All fields in the mutex structure may be used by a thread library
   however it wishes, however an implementation can use the fact that
   the .sm_private field is null, or that the .sm_flags field is ~0, to
   identify an unused static mutex. */

typedef struct __sdethread_mutex {
    void *		sm_private;	/* for use by thread library */
    unsigned int	sm_flags;	/* for use by thread library */
    const char *	sm_name;	/* diagnostic name */
    unsigned long	sm_unused[29];	/* for use by thread library */
} __sdethread_mutex_t;

#define __SDETHREAD_MUTEX_INITIALIZER(name)	\
    {0, ~0, name, {}}

/* Initialise a dynamically allocated mutex -- statically allocated mutexes
   are initialised using the initializer above. */
int	__sdethread_mutex_init (__sdethread_mutex_t *, const char *);

/* Release resources when a allocated mutex is no longer required. */
int	__sdethread_mutex_destroy (__sdethread_mutex_t *);

/* Acquire a mutex, blocking until done. Return zero for success. */
int	__sdethread_mutex_lock (__sdethread_mutex_t *);

/* Acquire a mutex, but don't block. Return zero for success, or
   non-zero if already locked. */
int	__sdethread_mutex_trylock (__sdethread_mutex_t *);

/* Unlock a mutex. Return zero for success. */
int	__sdethread_mutex_unlock (__sdethread_mutex_t *);

/*
 * ONCE 
 */

typedef struct {
    unsigned int	so_state;	/* used by this file */
    unsigned long	so_unused[15];	/* for use by thread library */
} __sdethread_once_t;

#define __SDETHREAD_ONCE_NEVER		0
#define __SDETHREAD_ONCE_INPROGRESS	1
#define __SDETHREAD_ONCE_DONE		2
#define __SDETHREAD_ONCE_INIT 		{ __SDETHREAD_ONCE_NEVER, {} }

/* Worker function: guarantees that __func is only called once
   (i.e. when __once->state == __SDETHREAD_ONCE_NEVER), and only
   returns when it has completed (i.e. when it is no longer "in
   progress"). */
int (__sdethread_once) (__sdethread_once_t *, void (*)(void));

#if defined(__OPTIMIZE__)
/* Optimize usual case */
int ___sdethread_once (__sdethread_once_t *, void (*)(void));
#define __sdethread_once(once, func) \
  ((once)->so_state == __SDETHREAD_ONCE_DONE \
       ? 0 : ___sdethread_once (once, func))
#endif

/* 
 * THREAD-SPECIFIC DATA 
 */

/* A globally visible thread-specific data key id. */
typedef long __sdethread_key_t;

/* Create a new global key, returning id via the first pointer
   argument, and returning zero for success. The destructor function
   pointer should be called when a thread is terminated, if that
   thread has a non-zero value set for the key, and with that value
   passed as argument to the destructor. */
int 	__sdethread_key_create (__sdethread_key_t *, void (*)(void *));

/* Delete a global key, but only if no threads have a non-zero data
   value assigned to the key. If possible don't reuse the same key
   again. Return zero when key is unused and deleted. */
/* XXX Currently unused -- safe to return non-zero in all cases */
int 	__sdethread_key_delete (__sdethread_key_t);

/* Set the thread-specific data value for the given key. */
int 	__sdethread_setspecific (__sdethread_key_t, const void *);

/* Return the thread-specific data value for the given key -- should
   be fast! */
void *	__sdethread_getspecific (__sdethread_key_t);

/* 
 * THREAD-SPECIFIC ERRNO 
 */

/* Return a pointer to the current thread's errno variable. */
int *	__sdethread_errno_pointer (void) __attribute__ ((__const__));

/* Assembler library module support function: set current thread's
  errno to the first argument, and then return its second argument. */
__attribute__((__nomips16__))
int	__sdethread_set_errno (int, int);


/* 
 * ASYNCHRONOUS SIGNAL/CANCELLATION HANDLING 
 * 
 * If the RTOS does not support asynchronous signals and/or thread
 * cancellation, then these are no-ops.
 */

/* Structure in which to save signal and cancellation state. */
typedef struct {
    unsigned long	ss_unused[8];	/* for use by thread library */
} __sdethread_sigstate_t;

/* Defer asynchronous signals and cancellations, saving old state. */
void	__sdethread_sigdisable (__sdethread_sigstate_t *);

/* Restore old signal mask and cancellation enable state. */
void	__sdethread_sigrestore (const __sdethread_sigstate_t *);

/* Return true if a deferred signal is pending. */
int	__sdethread_sigdeferred (void);


/* 
 * STDIO FILE LOCKS 
 */

/* __sdethread_flock_t is an opaque lock handle, allocated by the RTOS layer. */
struct __sdethread_flock;
typedef struct __sdethread_flock * __sdethread_flock_t;

/* Initialise file-locking interface -- called once by C library if
   file locks are required. The first argument is a destructor in the
   C library which should be called by the RTOS when a thread is
   terminated, to release any held file locks. */
void	__sdethread_flock_init (void (*) (void));

/* Create a new file lock handle, returning it and storing it in the
   location pointed to by the first argument; the second argument is
   the POSIX file descriptor, for diagnostics only. */
__sdethread_flock_t __sdethread_flock_create (__sdethread_flock_t *, int);

/* Acquire a file lock, blocking until available -- the lock is
   "recursive" in that a single thread may acquire the same lock
   repeatedly, which should simply increment the lock count without
   deadlocking. */
void	__sdethread_flock_lock (__sdethread_flock_t);

/* Acquire a lock / increment lock count, but don't block: return zero
   for success, non-zero for failure. */
int 	__sdethread_flock_trylock (__sdethread_flock_t);

/* Decrement file lock count, and release lock when zero. */
void 	__sdethread_flock_unlock (__sdethread_flock_t);

/* Forcibly release a lock held by current thread, e.g. called when a
   thread is terminated, but file lock may still be acquired by other
   threads. */
void 	__sdethread_flock_release (__sdethread_flock_t);

/* Release any lock held by current thread, and free the lock handle
  (e.g. when a file is closed). */
void 	__sdethread_flock_free (__sdethread_flock_t);


/*
 * THREADING ACTIVE FLAG
 *
 * Its mere existence indicates that the application is linked with a
 * threaded RTOS or library.
 */
extern int __sdethread_threading __attribute__ ((weak));

/*
 * INTERRUPT CONTROL
 *
 * Threaded RTOS specific interrupt control.
 */
void	__sdethread_intr_enable_all (void) __attribute__ ((weak));
int	__sdethread_intr_disable_all (void) __attribute__ ((weak));
int	__sdethread_intr_setmask (int) __attribute__ ((weak));

#ifdef __cplusplus
}
#endif

#endif /* __SDETHREAD_H */
