1
0
mirror of https://git.FreeBSD.org/src.git synced 2024-12-04 09:09:56 +00:00

Submitted by: John Birrell <cimaxp1!jb@werple.net.au>

Here are the diffs for libc_r to get it one step closer to P1003.1c
These make most of the thread/mutex/condvar structures opaque to the
user. There are three functions which have been renamed with _np
suffixes because they are extensions to P1003.1c (I did them for JAVA,
which needs to suspend/resume threads and also start threads suspended).

I've created a new header (pthread_np.h) for the non-POSIX stuff.

The egrep tags stuff in /usr/src/lib/libc_r/Makefile that I uncommented
doesn't work. I think its best to delete it. I don't think libc_r needs
tags anyway, 'cause most of the source is in libc which does have tags.

also:

Here's the first batch of man pages for the thread functions.
The diff to /usr/src/lib/libc_r/Makefile removes some stuff that was
inherited from /usr/src/lib/libc/Makefile that should only be done with
libc.

also:

I should have sent this diff with the pthread(3) man page.
It allows people to type

make -DWANT_LIBC_R world

to get libc_r built with the rest of the world. I put this in the
pthread(3) man page.  The default is still not to build libc_r.


also:
The diff attached adds a pthread(3) man page to /usr/src/share/man/man3.
The idea is that without libc_r installed, this man page will give people
enough info to know that they have to build libc_r.
This commit is contained in:
Julian Elischer 1996-08-20 08:22:01 +00:00
parent 1bbb22c82e
commit 0f7d684755
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=17706
143 changed files with 8344 additions and 2010 deletions

View File

@ -1,5 +1,5 @@
# From: @(#)Makefile 8.2 (Berkeley) 1/4/94
# $Id: Makefile,v 1.38 1996/07/09 15:48:20 ache Exp $
# $Id: Makefile,v 1.39 1996/08/04 22:34:23 wosch Exp $
#
# Doing a make install builds /usr/include
#
@ -13,10 +13,10 @@ SUBDIR= rpcsvc
FILES= a.out.h ar.h assert.h bitstring.h ctype.h db.h dirent.h disktab.h \
err.h f2c.h fnmatch.h fstab.h fts.h glob.h grp.h strhash.h histedit.h \
kvm.h limits.h link.h locale.h malloc.h memory.h mpool.h ndbm.h \
netdb.h nl_types.h nlist.h paths.h pthread.h pwd.h ranlib.h regex.h \
regexp.h resolv.h rune.h runetype.h setjmp.h sgtty.h signal.h \
stab.h stddef.h stdio.h stdlib.h string.h strings.h struct.h \
sysexits.h tar.h time.h timers.h ttyent.h unistd.h utime.h \
netdb.h nl_types.h nlist.h paths.h pthread.h pthread_np.h pwd.h \
ranlib.h regex.h regexp.h resolv.h rune.h runetype.h setjmp.h sgtty.h \
signal.h stab.h stddef.h stdio.h stdlib.h string.h strings.h \
struct.h sysexits.h tar.h time.h timers.h ttyent.h unistd.h utime.h \
utmp.h vis.h
.if defined(WANT_CSRG_LIBM)
FILES+= math.h

View File

@ -40,141 +40,77 @@
#include <sys/cdefs.h>
#include <sys/types.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <limits.h>
/*
* Forward thread structure definition. This is opaque to the user.
* Run-time invariant values:
*/
#define PTHREAD_DESTRUCTOR_ITERATIONS 4
#define PTHREAD_KEYS_MAX 256
#define PTHREAD_STACK_MIN 1024
#define PTHREAD_THREADS_MAX ULONG_MAX
/*
* Compile time symbolic constants for portability specifications:
*
* Note that those commented out are not currently supported by the
* implementation.
*/
#define _POSIX_THREADS
#define _POSIX_THREAD_ATTR_STACKADDR
#define _POSIX_THREAD_ATTR_STACKSIZE
#define _POSIX_THREAD_PRIORITY_SCHEDULING
/* #define _POSIX_THREAD_PRIO_INHERIT */
/* #define _POSIX_THREAD_PRIO_PROTECT */
/* #define _POSIX_THREAD_PROCESS_SHARED */
#define _POSIX_THREAD_SAFE_FUNCTIONS
/*
* Forward structure definitions.
*
* These are mostly opaque to the user.
*/
struct pthread;
struct pthread_attr;
struct pthread_cond;
struct pthread_cond_attr;
struct pthread_mutex;
struct pthread_mutex_attr;
struct pthread_once;
struct sched_param;
/*
* Queue definitions.
* Primitive system data type definitions required by P1003.1c.
*
* Note that P1003.1c specifies that there are no defined comparison
* or assignment operators for the types pthread_attr_t, pthread_cond_t,
* pthread_condattr_t, pthread_mutex_t, pthread_mutexattr_t.
*/
struct pthread_queue {
struct pthread *q_next;
struct pthread *q_last;
void *q_data;
};
typedef struct pthread *pthread_t;
typedef struct pthread_attr *pthread_attr_t;
typedef struct pthread_mutex *pthread_mutex_t;
typedef struct pthread_mutex_attr *pthread_mutexattr_t;
typedef struct pthread_cond *pthread_cond_t;
typedef struct pthread_cond_attr *pthread_condattr_t;
typedef int pthread_key_t;
typedef struct pthread_once pthread_once_t;
/*
* Static queue initialization values.
* Additional type definitions:
*
* Note that P1003.1c reserves the prefixes pthread_ and PTHREAD_ for
* use in header symbols.
*/
#define PTHREAD_QUEUE_INITIALIZER { NULL, NULL, NULL }
/*
* Mutex definitions.
*/
enum pthread_mutextype {
MUTEX_TYPE_FAST = 1,
MUTEX_TYPE_COUNTING_FAST = 2, /* Recursive */
MUTEX_TYPE_MAX
};
union pthread_mutex_data {
void *m_ptr;
int m_count;
};
struct pthread_mutex {
enum pthread_mutextype m_type;
struct pthread_queue m_queue;
struct pthread *m_owner;
union pthread_mutex_data m_data;
long m_flags;
};
/*
* Flags for mutexes.
*/
#define MUTEX_FLAGS_PRIVATE 0x01
#define MUTEX_FLAGS_INITED 0x02
#define MUTEX_FLAGS_BUSY 0x04
/*
* Static mutex initialization values.
*/
#define PTHREAD_MUTEX_INITIALIZER \
{ MUTEX_TYPE_FAST, PTHREAD_QUEUE_INITIALIZER, \
NULL, { NULL }, MUTEX_FLAGS_INITED }
struct pthread_mutex_attr {
enum pthread_mutextype m_type;
long m_flags;
};
/*
* Condition variable definitions.
*/
enum pthread_cond_type {
COND_TYPE_FAST,
COND_TYPE_MAX
};
struct pthread_cond {
enum pthread_cond_type c_type;
struct pthread_queue c_queue;
void *c_data;
long c_flags;
};
struct pthread_cond_attr {
enum pthread_cond_type c_type;
long c_flags;
};
/*
* Flags for condition variables.
*/
#define COND_FLAGS_PRIVATE 0x01
#define COND_FLAGS_INITED 0x02
#define COND_FLAGS_BUSY 0x04
/*
* Static cond initialization values.
*/
#define PTHREAD_COND_INITIALIZER \
{ COND_TYPE_FAST, PTHREAD_QUEUE_INITIALIZER, NULL, COND_FLAGS_INITED }
/*
* Cleanup definitions.
*/
struct pthread_cleanup {
struct pthread_cleanup *next;
void (*routine) ();
void *routine_arg;
};
/*
* Scheduling definitions.
*/
enum schedparam_policy {
SCHED_RR,
SCHED_IO,
SCHED_FIFO,
SCHED_OTHER
};
struct pthread_attr {
enum schedparam_policy schedparam_policy;
int prio;
int suspend;
int flags;
void *arg_attr;
void (*cleanup_attr) ();
void *stackaddr_attr;
size_t stacksize_attr;
};
struct sched_param {
int prio;
void *no_data;
};
typedef void *pthread_addr_t;
typedef void *(*pthread_startroutine_t) (void *);
/*
* Once definitions.
*/
struct pthread_once {
int state;
struct pthread_mutex mutex;
int state;
pthread_mutex_t mutex;
};
/*
@ -186,21 +122,7 @@ struct pthread_once {
/*
* Static once initialization values.
*/
#define PTHREAD_ONCE_INIT { PTHREAD_NEEDS_INIT, PTHREAD_MUTEX_INITIALIZER }
/*
* Type definitions.
*/
typedef int pthread_key_t;
typedef struct pthread *pthread_t;
typedef struct pthread_attr pthread_attr_t;
typedef struct pthread_cond pthread_cond_t;
typedef struct pthread_cond_attr pthread_condattr_t;
typedef struct pthread_mutex pthread_mutex_t;
typedef struct pthread_mutex_attr pthread_mutexattr_t;
typedef struct pthread_once pthread_once_t;
typedef void *pthread_addr_t;
typedef void *(*pthread_startroutine_t) (void *);
#define PTHREAD_ONCE_INIT { PTHREAD_NEEDS_INIT, NULL }
/*
* Default attribute arguments.
@ -215,62 +137,95 @@ typedef void *(*pthread_startroutine_t) (void *);
* Thread function prototype definitions:
*/
__BEGIN_DECLS
int pthread_create __P((pthread_t *, const pthread_attr_t *,
void *(*start_routine) (void *), void *));
void pthread_exit __P((void *));
pthread_t pthread_self __P((void));
int pthread_equal __P((pthread_t, pthread_t));
int pthread_getprio __P((pthread_t));
int pthread_setprio __P((pthread_t, int));
int pthread_join __P((pthread_t, void **));
int pthread_detach __P((pthread_t *));
int pthread_resume __P((pthread_t));
int pthread_suspend __P((pthread_t));
void pthread_yield __P((void));
int pthread_setschedparam __P((pthread_t pthread, int policy,
struct sched_param * param));
int pthread_getschedparam __P((pthread_t pthread, int *policy,
struct sched_param * param));
int pthread_kill __P((struct pthread *, int));
int pthread_cleanup_push __P((void (*routine) (void *), void *routine_arg));
void pthread_cleanup_pop __P((int execute));
int pthread_cond_init __P((pthread_cond_t *, const pthread_condattr_t *));
int pthread_cond_timedwait __P((pthread_cond_t *, pthread_mutex_t *,
const struct timespec * abstime));
int pthread_cond_wait __P((pthread_cond_t *, pthread_mutex_t *));
int pthread_cond_signal __P((pthread_cond_t *));
int pthread_cond_broadcast __P((pthread_cond_t *));
int pthread_cond_destroy __P((pthread_cond_t *));
int pthread_mutex_init __P((pthread_mutex_t *, const pthread_mutexattr_t *));
int pthread_mutex_lock __P((pthread_mutex_t *));
int pthread_mutex_unlock __P((pthread_mutex_t *));
int pthread_mutex_trylock __P((pthread_mutex_t *));
int pthread_mutex_destroy __P((pthread_mutex_t *));
int pthread_attr_init __P((pthread_attr_t *));
int pthread_attr_destroy __P((pthread_attr_t *));
int pthread_attr_setstacksize __P((pthread_attr_t *, size_t));
int pthread_attr_getstacksize __P((pthread_attr_t *, size_t *));
int pthread_attr_setstackaddr __P((pthread_attr_t *, void *));
int pthread_attr_getstackaddr __P((pthread_attr_t *, void **));
int pthread_attr_setdetachstate __P((pthread_attr_t *, int));
int pthread_attr_getdetachstate __P((pthread_attr_t *, int *));
int pthread_attr_setscope __P((pthread_attr_t *, int));
int pthread_attr_getscope __P((pthread_attr_t *, int *));
int pthread_attr_setinheritsched __P((pthread_attr_t *, int));
int pthread_attr_getinheritsched __P((pthread_attr_t *, int *));
int pthread_attr_setschedpolicy __P((pthread_attr_t *, int));
int pthread_attr_getschedpolicy __P((pthread_attr_t *, int *));
int pthread_attr_setschedparam __P((pthread_attr_t *, struct sched_param *));
int pthread_attr_getschedparam __P((pthread_attr_t *, struct sched_param *));
int pthread_attr_setfloatstate __P((pthread_attr_t *, int));
int pthread_attr_getfloatstate __P((pthread_attr_t *, int *));
int pthread_attr_setcleanup __P((pthread_attr_t *, void (*routine) (void *), void *));
int pthread_attr_setcreatesuspend __P((pthread_attr_t *));
int pthread_once __P((pthread_once_t *, void (*init_routine) (void)));
int pthread_keycreate __P((pthread_key_t *, void (*routine) (void *)));
int pthread_setspecific __P((pthread_key_t, const void *));
int pthread_getspecific __P((pthread_key_t, void **));
int pthread_key_delete __P((pthread_key_t));
int pthread_attr_destroy __P((pthread_attr_t *));
int pthread_attr_getinheritsched __P((pthread_attr_t *, int *));
int pthread_attr_getschedparam __P((pthread_attr_t *,
struct sched_param *));
int pthread_attr_getschedpolicy __P((pthread_attr_t *, int *));
int pthread_attr_getscope __P((pthread_attr_t *, int *));
int pthread_attr_getstacksize __P((pthread_attr_t *, size_t *));
int pthread_attr_getstackaddr __P((pthread_attr_t *, void **));
int pthread_attr_getdetachstate __P((pthread_attr_t *, int *));
int pthread_attr_init __P((pthread_attr_t *));
int pthread_attr_setinheritsched __P((pthread_attr_t *, int));
int pthread_attr_setschedparam __P((pthread_attr_t *,
struct sched_param *));
int pthread_attr_setschedpolicy __P((pthread_attr_t *, int));
int pthread_attr_setscope __P((pthread_attr_t *, int));
int pthread_attr_setstacksize __P((pthread_attr_t *, size_t));
int pthread_attr_setstackaddr __P((pthread_attr_t *, void *));
int pthread_attr_setdetachstate __P((pthread_attr_t *, int));
void pthread_cleanup_pop __P((int execute));
int pthread_cleanup_push __P((void (*routine) (void *),
void *routine_arg));
int pthread_condattr_destroy __P((pthread_condattr_t *attr));
int pthread_condattr_init __P((pthread_condattr_t *attr));
int pthread_condattr_getpshared __P((pthread_condattr_t *attr,
int *pshared));
int pthread_condattr_setpshared __P((pthread_condattr_t *attr,
int pshared));
int pthread_cond_broadcast __P((pthread_cond_t *));
int pthread_cond_destroy __P((pthread_cond_t *));
int pthread_cond_init __P((pthread_cond_t *,
const pthread_condattr_t *));
int pthread_cond_signal __P((pthread_cond_t *));
int pthread_cond_timedwait __P((pthread_cond_t *,
pthread_mutex_t *, const struct timespec * abstime));
int pthread_cond_wait __P((pthread_cond_t *, pthread_mutex_t *));
int pthread_create __P((pthread_t *, const pthread_attr_t *,
void *(*start_routine) (void *), void *));
int pthread_detach __P((pthread_t *));
int pthread_equal __P((pthread_t, pthread_t));
void pthread_exit __P((void *));
int pthread_getspecific __P((pthread_key_t, void **));
int pthread_join __P((pthread_t, void **));
int pthread_key_create __P((pthread_key_t *,
void (*routine) (void *)));
int pthread_key_delete __P((pthread_key_t));
int pthread_kill __P((struct pthread *, int));
int pthread_mutexattr_destroy __P((pthread_mutexattr_t *));
int pthread_mutexattr_getprioceiling __P((pthread_mutexattr_t *,
int *prioceiling));
int pthread_mutexattr_getprotocol __P((pthread_mutexattr_t *,
int *protocol));
int pthread_mutexattr_getpshared __P((pthread_mutexattr_t *,
int *pshared));
int pthread_mutexattr_init __P((pthread_mutexattr_t *));
int pthread_mutexattr_setprioceiling __P((pthread_mutexattr_t *,
int prioceiling));
int pthread_mutexattr_setprotocol __P((pthread_mutexattr_t *,
int protocol));
int pthread_mutexattr_setpshared __P((pthread_mutexattr_t *,
int pshared));
int pthread_mutex_destroy __P((pthread_mutex_t *));
int pthread_mutex_getprioceiling __P((pthread_mutex_t *));
int pthread_mutex_init __P((pthread_mutex_t *,
const pthread_mutexattr_t *));
int pthread_mutex_lock __P((pthread_mutex_t *));
int pthread_mutex_setprioceiling __P((pthread_mutex_t *));
int pthread_mutex_trylock __P((pthread_mutex_t *));
int pthread_mutex_unlock __P((pthread_mutex_t *));
int pthread_once __P((pthread_once_t *,
void (*init_routine) (void)));
pthread_t pthread_self __P((void));
int pthread_setcancelstate __P((int, int *));
int pthread_setcanceltype __P((int, int *));
int pthread_setspecific __P((pthread_key_t, const void *));
int pthread_sigmask __P((int, const sigset_t *, sigset_t *));
int pthread_testcancel __P((void));
int pthread_getprio __P((pthread_t));
int pthread_setprio __P((pthread_t, int));
void pthread_yield __P((void));
int pthread_setschedparam __P((pthread_t pthread, int policy,
struct sched_param * param));
int pthread_getschedparam __P((pthread_t pthread, int *policy,
struct sched_param * param));
int pthread_attr_setfloatstate __P((pthread_attr_t *, int));
int pthread_attr_getfloatstate __P((pthread_attr_t *, int *));
int pthread_attr_setcleanup __P((pthread_attr_t *,
void (*routine) (void *), void *));
__END_DECLS
#endif

47
include/pthread_np.h Normal file
View File

@ -0,0 +1,47 @@
/*
* Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Birrell.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
*
*/
#ifndef _PTHREAD_NP_H_
#define _PTHREAD_NP_H_
/*
* Non-POSIX thread function prototype definitions:
*/
__BEGIN_DECLS
int pthread_attr_setcreatesuspend_np __P((pthread_attr_t *));
int pthread_multi_np __P((void));
int pthread_resume_np __P((pthread_t));
int pthread_single_np __P((void));
int pthread_suspend_np __P((pthread_t));
__END_DECLS
#endif

View File

@ -16,6 +16,10 @@ SUBDIR+=libc libcompat libcom_err libcurses libdisk libedit \
libscsi libskey libss libtcl libtermcap libutil libxpg4 liby libz
.if defined(WANT_LIBC_R)
SUBDIR+= libc_r
.endif
.if !exists(../secure) || defined(NOSECURE) || defined(NOCRYPT)
SUBDIR+= libcrypt
.else

View File

@ -35,7 +35,7 @@
*
* from: @(#)SYS.h 5.5 (Berkeley) 5/7/91
*
* $Id: SYS.h,v 1.3 1996/01/22 00:00:51 julian Exp $
* $Id: SYS.h,v 1.4 1996/05/05 07:56:03 peter Exp $
*/
#include <sys/syscall.h>
@ -64,20 +64,38 @@
#define SYSCALL(x) 2: PIC_PROLOGUE; jmp PIC_PLT(HIDENAME(cerror)); ENTRY(x); lea __CONCAT(SYS_,x),%eax; KERNCALL; jb 2b
#define RSYSCALL(x) SYSCALL(x); ret
/*
* For the thread_safe versions, we prepend _thread_sys_ to the function
* name so that the 'C' wrapper can go around the real name.
*/
#ifdef _THREAD_SAFE /* in case */
#define PSYSCALL(x,y) 2: PIC_PROLOGUE; jmp PIC_PLT(HIDENAME(cerror)); ENTRY(y); lea __CONCAT(SYS_,x),%eax; KERNCALL; jb 2b
#define PRSYSCALL(x,y) PSYSCALL(x,y); ret
#endif
#define PSEUDO(x,y) ENTRY(x); lea __CONCAT(SYS_,y), %eax; KERNCALL; ret
#define CALL(x,y) call CNAME(y); addl $4*x,%esp
/* gas fucks up offset -- although we don't currently need it, do for BCS */
#define LCALL(x,y) .byte 0x9a ; .long y; .word x
/*
* Design note:
*
* The macros PSYSCALL() and PRSYSCALL() are intended for use where a
* syscall needs to be renamed in the threaded library. When building
* a normal library, they default to the traditional SYSCALL() and
* RSYSCALL(). This avoids the need to #ifdef _THREAD_SAFE everywhere
* that the renamed function needs to be called.
*/
#ifdef _THREAD_SAFE /* in case */
/*
* For the thread_safe versions, we prepend _thread_sys_ to the function
* name so that the 'C' wrapper can go around the real name.
*/
#define PSYSCALL(x) 2: PIC_PROLOGUE; jmp PIC_PLT(HIDENAME(cerror)); ENTRY(_thread_sys_/**/x); lea __CONCAT(SYS_,x),%eax; KERNCALL; jb 2b
#define PRSYSCALL(x) PSYSCALL(x); ret
#define PPSEUDO(x,y) ENTRY(_thread_sys_/**/x); lea __CONCAT(SYS_,y), %eax; KERNCALL; ret
#else
/*
* The non-threaded library defaults to traditional syscalls where
* the function name matches the syscall name.
*/
#define PSYSCALL(x) SYSCALL(x)
#define PRSYSCALL(x) RSYSCALL(x)
#define PPSEUDO(x,y) PSEUDO(x,y)
#endif
#ifdef __ELF__
#define KERNCALL int $0x80 /* Faster */
#else

View File

@ -33,21 +33,17 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: pipe.S,v 1.3 1996/01/22 00:00:58 julian Exp $
* $Id: pipe.S,v 1.4 1996/05/05 07:56:13 peter Exp $
*/
#if defined(SYSLIBC_RCS) && !defined(lint)
.text
.asciz "$Id: pipe.S,v 1.3 1996/01/22 00:00:58 julian Exp $"
.asciz "$Id: pipe.S,v 1.4 1996/05/05 07:56:13 peter Exp $"
#endif /* SYSLIBC_RCS and not lint */
#include "SYS.h"
#ifdef _THREAD_SAFE
PSYSCALL(pipe,_thread_sys_pipe)
#else
SYSCALL(pipe)
#endif
PSYSCALL(pipe)
movl 4(%esp),%ecx
movl %eax,(%ecx)
movl %edx,4(%ecx)

View File

@ -33,12 +33,12 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: sigreturn.S,v 1.3 1996/01/22 00:01:00 julian Exp $
* $Id: sigreturn.S,v 1.4 1996/05/05 07:56:19 peter Exp $
*/
#if defined(SYSLIBC_RCS) && !defined(lint)
.text
.asciz "$Id: sigreturn.S,v 1.3 1996/01/22 00:01:00 julian Exp $"
.asciz "$Id: sigreturn.S,v 1.4 1996/05/05 07:56:19 peter Exp $"
#endif /* SYSLIBC_RCS and not lint */
#include "SYS.h"
@ -48,9 +48,5 @@
* must be saved. On FreeBSD, this is not the case.
*/
#ifdef _THREAD_SAFE
PSYSCALL(sigreturn,_thread_sys_sigreturn)
#else
SYSCALL(sigreturn)
#endif
PSYSCALL(sigreturn)
ret

View File

@ -49,7 +49,8 @@ static char sccsid[] = "@(#)ttyname.c 8.2 (Berkeley) 1/27/94";
#ifdef _THREAD_SAFE
#include <pthread.h>
#include "pthread_private.h"
static pthread_mutex_t ttyname_lock = PTHREAD_MUTEX_INITIALIZER;
static struct pthread_mutex _ttyname_lockd = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t ttyname_lock = &_ttyname_lockd;
static pthread_key_t ttyname_key;
static int ttyname_init = 0;

View File

@ -35,7 +35,7 @@
*
* from: @(#)SYS.h 5.5 (Berkeley) 5/7/91
*
* $Id: SYS.h,v 1.3 1996/01/22 00:00:51 julian Exp $
* $Id: SYS.h,v 1.4 1996/05/05 07:56:03 peter Exp $
*/
#include <sys/syscall.h>
@ -64,20 +64,38 @@
#define SYSCALL(x) 2: PIC_PROLOGUE; jmp PIC_PLT(HIDENAME(cerror)); ENTRY(x); lea __CONCAT(SYS_,x),%eax; KERNCALL; jb 2b
#define RSYSCALL(x) SYSCALL(x); ret
/*
* For the thread_safe versions, we prepend _thread_sys_ to the function
* name so that the 'C' wrapper can go around the real name.
*/
#ifdef _THREAD_SAFE /* in case */
#define PSYSCALL(x,y) 2: PIC_PROLOGUE; jmp PIC_PLT(HIDENAME(cerror)); ENTRY(y); lea __CONCAT(SYS_,x),%eax; KERNCALL; jb 2b
#define PRSYSCALL(x,y) PSYSCALL(x,y); ret
#endif
#define PSEUDO(x,y) ENTRY(x); lea __CONCAT(SYS_,y), %eax; KERNCALL; ret
#define CALL(x,y) call CNAME(y); addl $4*x,%esp
/* gas fucks up offset -- although we don't currently need it, do for BCS */
#define LCALL(x,y) .byte 0x9a ; .long y; .word x
/*
* Design note:
*
* The macros PSYSCALL() and PRSYSCALL() are intended for use where a
* syscall needs to be renamed in the threaded library. When building
* a normal library, they default to the traditional SYSCALL() and
* RSYSCALL(). This avoids the need to #ifdef _THREAD_SAFE everywhere
* that the renamed function needs to be called.
*/
#ifdef _THREAD_SAFE /* in case */
/*
* For the thread_safe versions, we prepend _thread_sys_ to the function
* name so that the 'C' wrapper can go around the real name.
*/
#define PSYSCALL(x) 2: PIC_PROLOGUE; jmp PIC_PLT(HIDENAME(cerror)); ENTRY(_thread_sys_/**/x); lea __CONCAT(SYS_,x),%eax; KERNCALL; jb 2b
#define PRSYSCALL(x) PSYSCALL(x); ret
#define PPSEUDO(x,y) ENTRY(_thread_sys_/**/x); lea __CONCAT(SYS_,y), %eax; KERNCALL; ret
#else
/*
* The non-threaded library defaults to traditional syscalls where
* the function name matches the syscall name.
*/
#define PSYSCALL(x) SYSCALL(x)
#define PRSYSCALL(x) RSYSCALL(x)
#define PPSEUDO(x,y) PSEUDO(x,y)
#endif
#ifdef __ELF__
#define KERNCALL int $0x80 /* Faster */
#else

View File

@ -33,21 +33,17 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: fork.S,v 1.3 1996/01/22 00:00:57 julian Exp $
* $Id: fork.S,v 1.4 1996/05/05 07:56:13 peter Exp $
*/
#if defined(SYSLIBC_RCS) && !defined(lint)
.text
.asciz "$Id: fork.S,v 1.3 1996/01/22 00:00:57 julian Exp $"
.asciz "$Id: fork.S,v 1.4 1996/05/05 07:56:13 peter Exp $"
#endif /* SYSLIBC_RCS and not lint */
#include "SYS.h"
#ifdef _THREAD_SAFE
PSYSCALL(fork,_thread_sys_fork)
#else
SYSCALL(fork)
#endif
PSYSCALL(fork)
cmpl $0,%edx /* parent, since %edx == 0 in parent, 1 in child */
je 1f
movl $0,%eax

View File

@ -33,21 +33,17 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: pipe.S,v 1.3 1996/01/22 00:00:58 julian Exp $
* $Id: pipe.S,v 1.4 1996/05/05 07:56:13 peter Exp $
*/
#if defined(SYSLIBC_RCS) && !defined(lint)
.text
.asciz "$Id: pipe.S,v 1.3 1996/01/22 00:00:58 julian Exp $"
.asciz "$Id: pipe.S,v 1.4 1996/05/05 07:56:13 peter Exp $"
#endif /* SYSLIBC_RCS and not lint */
#include "SYS.h"
#ifdef _THREAD_SAFE
PSYSCALL(pipe,_thread_sys_pipe)
#else
SYSCALL(pipe)
#endif
PSYSCALL(pipe)
movl 4(%esp),%ecx
movl %eax,(%ecx)
movl %edx,4(%ecx)

View File

@ -33,21 +33,17 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: rfork.S,v 1.1 1996/02/23 19:56:47 peter Exp $
* $Id: rfork.S,v 1.2 1996/05/05 07:56:15 peter Exp $
*/
#if defined(SYSLIBC_RCS) && !defined(lint)
.text
.asciz "$Id: rfork.S,v 1.1 1996/02/23 19:56:47 peter Exp $"
.asciz "$Id: rfork.S,v 1.2 1996/05/05 07:56:15 peter Exp $"
#endif /* SYSLIBC_RCS and not lint */
#include "SYS.h"
#ifdef _THREAD_SAFE
PSYSCALL(rfork,_thread_sys_rfork)
#else
SYSCALL(rfork)
#endif
PSYSCALL(rfork)
cmpl $0,%edx /* parent, since %edx == 0 in parent, 1 in child */
je 1f
movl $0,%eax

View File

@ -33,21 +33,17 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: sigpending.S,v 1.3 1996/01/22 00:00:59 julian Exp $
* $Id: sigpending.S,v 1.4 1996/05/05 07:56:18 peter Exp $
*/
#if defined(SYSLIBC_RCS) && !defined(lint)
.text
.asciz "$Id: sigpending.S,v 1.3 1996/01/22 00:00:59 julian Exp $"
.asciz "$Id: sigpending.S,v 1.4 1996/05/05 07:56:18 peter Exp $"
#endif /* SYSLIBC_RCS and not lint */
#include "SYS.h"
#ifdef _THREAD_SAFE
PSYSCALL(sigpending,_thread_sys_sigpending)
#else
SYSCALL(sigpending)
#endif
PSYSCALL(sigpending)
movl 4(%esp),%ecx # fetch pointer to...
movl %eax,(%ecx) # store old mask
xorl %eax,%eax

View File

@ -33,12 +33,12 @@
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*
* $Id: sigreturn.S,v 1.3 1996/01/22 00:01:00 julian Exp $
* $Id: sigreturn.S,v 1.4 1996/05/05 07:56:19 peter Exp $
*/
#if defined(SYSLIBC_RCS) && !defined(lint)
.text
.asciz "$Id: sigreturn.S,v 1.3 1996/01/22 00:01:00 julian Exp $"
.asciz "$Id: sigreturn.S,v 1.4 1996/05/05 07:56:19 peter Exp $"
#endif /* SYSLIBC_RCS and not lint */
#include "SYS.h"
@ -48,9 +48,5 @@
* must be saved. On FreeBSD, this is not the case.
*/
#ifdef _THREAD_SAFE
PSYSCALL(sigreturn,_thread_sys_sigreturn)
#else
SYSCALL(sigreturn)
#endif
PSYSCALL(sigreturn)
ret

View File

@ -24,8 +24,8 @@
*/
#if defined(LIBC_SCCS) && !defined(lint)
static char sccsid[] = "@(#)$Id: gethostnamadr.c,v 1.7 1995/05/30 05:40:45 rgrimes Exp $";
static char rcsid[] = "$Id: gethostnamadr.c,v 1.7 1995/05/30 05:40:45 rgrimes Exp $";
static char sccsid[] = "@(#)$Id: gethostnamadr.c,v 1.8 1996/07/12 18:54:36 jkh Exp $";
static char rcsid[] = "$Id: gethostnamadr.c,v 1.8 1996/07/12 18:54:36 jkh Exp $";
#endif /* LIBC_SCCS and not lint */
#include <sys/param.h>
@ -184,6 +184,27 @@ gethostbyaddr(const char *addr, int len, int type)
return hp;
}
#ifdef _THREAD_SAFE
struct hostent_data;
/*
* Temporary function (not thread safe)
*/
int gethostbyaddr_r(const char *addr, int len, int type,
struct hostent *result, struct hostent_data *buffer)
{
struct hostent *hp = 0;
int ret;
if ((hp = gethostbyaddr(addr, len, type)) == NULL) {
ret = -1;
} else {
memcpy(result, hp, sizeof(struct hostent));
ret = 0;
}
return(ret);
}
#endif
void
sethostent(stayopen)
int stayopen;

View File

@ -168,8 +168,10 @@ static char lcl_TZname[TZ_STRLEN_MAX + 1];
static int lcl_is_set;
static int gmt_is_set;
#ifdef _THREAD_SAFE
static pthread_mutex_t lcl_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t gmt_mutex = PTHREAD_MUTEX_INITIALIZER;
static struct pthread_mutex _lcl_mutexd = PTHREAD_MUTEX_INITIALIZER;
static struct pthread_mutex _gmt_mutexd = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t lcl_mutex = &_lcl_mutexd;
static pthread_mutex_t gmt_mutex = &_gmt_mutexd;
#endif
char * tzname[2] = {
@ -1087,7 +1089,8 @@ localtime(timep)
const time_t * const timep;
{
#ifdef _THREAD_SAFE
static pthread_mutex_t localtime_mutex = PTHREAD_MUTEX_INITIALIZER;
static struct pthread_mutex _localtime_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t localtime_mutex = &_localtime_mutex;
static pthread_key_t localtime_key = -1;
struct tm *p_tm;
@ -1170,7 +1173,8 @@ gmtime(timep)
const time_t * const timep;
{
#ifdef _THREAD_SAFE
static pthread_mutex_t gmtime_mutex = PTHREAD_MUTEX_INITIALIZER;
static struct pthread_mutex _gmtime_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_mutex_t gmtime_mutex = &_gmtime_mutex;
static pthread_key_t gmtime_key = -1;
struct tm *p_tm;

View File

@ -20,6 +20,7 @@ PRECIOUSLIB= yes
.include "${.CURDIR}/gen/Makefile.inc"
.include "${.CURDIR}/gmon/Makefile.inc"
.include "${.CURDIR}/locale/Makefile.inc"
.include "${.CURDIR}/man/Makefile.inc"
.include "${.CURDIR}/net/Makefile.inc"
.include "${.CURDIR}/nls/Makefile.inc"
.include "${.CURDIR}/quad/Makefile.inc"
@ -38,24 +39,8 @@ CFLAGS+= -DYP
.endif
.include "${.CURDIR}/${MACHINE}/sys/Makefile.inc"
KQSRCS= adddi3.c anddi3.c ashldi3.c ashrdi3.c cmpdi2.c divdi3.c iordi3.c \
lshldi3.c lshrdi3.c moddi3.c muldi3.c negdi2.c notdi2.c qdivrem.c \
subdi3.c ucmpdi2.c udivdi3.c umoddi3.c xordi3.c
KSRCS= bcmp.c ffs.c index.c mcount.c rindex.c strcat.c strcmp.c strcpy.c \
strlen.c strncpy.c
libkern: libkern.gen libkern.${MACHINE}
libkern.gen: ${KQSRCS} ${KSRCS}
cp -p ${.CURDIR}/quad/quad.h ${.ALLSRC} /sys/libkern
libkern.${MACHINE}:: ${KMSRCS}
.if defined(KMSRCS) && !empty(KMSRCS)
cp -p ${.ALLSRC} /sys/libkern/${MACHINE}
.endif
#beforeinstall: tags
# ${INSTALL} ${COPY} -o bin -g bin -m 444 tags /var/db/libc.tags
beforeinstall: tags
${INSTALL} ${COPY} -o bin -g bin -m 444 tags /var/db/libc_r.tags
tags: ${SRCS}
ctags ${.ALLSRC:M*.c}

View File

@ -0,0 +1,17 @@
# $Id$
# POSIX thread man files
.PATH: ${.CURDIR}/man
MAN3+= pthread_create.3 \
pthread_detach.3 \
pthread_equal.3 \
pthread_exit.3 \
pthread_getspecific.3 \
pthread_join.3 \
pthread_key_create.3 \
pthread_key_delete.3 \
pthread_once.3 \
pthread_self.3 \
pthread_setspecific.3

View File

@ -0,0 +1,109 @@
.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. 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.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by John Birrell.
.\" 4. Neither the name of the author nor the names of any co-contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
.\"
.Dd April 4, 1996
.Dt PTHREAD_CREATE 3
.Os BSD 4
.Sh NAME
.Nm pthread_create
.Nd create a new thread
.Sh SYNOPSIS
.Fd #include <pthread.h>
.Ft int
.Fn pthread_create "pthread_t *thread" "const pthread_attr_t *attr" "void *(*start_routine)(void *)" "void *arg"
.Sh DESCRIPTION
The
.Fn pthread_create
function is used to create a new thread, with attributes specified by
.Fa attr ,
within a process. If
.Fa attr
is NULL, the default attributes are used. If the attributes specified by
.Fa attr
are modified later, the thread's attributes are not affected. Upon
successful completion
.Fn pthread_create
will store the ID of the created thread in the location specified by
.Fa thread .
.Pp
The thread is created executing
.Fa start_routine
with
.Fa arg
as its sole argument. If the
.Fa start_routine
returns, the effect is as if there was an implicit call to
.Fn pthread_exit
using the return value of
.Fa start_toutine
as the exit status. Note that the thread in which
.Fn main
was originally invoked differs from this. When it returns from
.Fn main ,
the effect is as if there was an implicit call to
.Fn exit using the return value of
.Fn main
as the exit status.
.Pp
The signal state of the new thread is initialized as:
.Bl -bullet -offset indent
.It
The signal mask is inherited from the creating thread.
.It
The set of signals pending for the new thread is empty.
.El
.Sh RETURN VALUES
If successful, the
.Fn pthread_create
function will return zero. Otherwise an error number will be returned to
indicate the error.
.Sh ERRORS
.Fn pthread_create
will fail if:
.Bl -tag -width Er
.It Bq Er EAGAIN
The system lacked the necessary resources to create another thread, or
the system-imposed limit on the total number of threads in a process
[PTHREAD_THREADS_MAX] would be exceeded.
.It Bq Er EINVAL
The value specified by
.Fa attr
is invalid.
.El
.Pp
.Sh SEE ALSO
.Xr pthread_exit 3 ,
.Xr pthread_join 3 ,
.Xr fork 2
.Sh STANDARDS
.Fn pthread_create
is expected to conform to IEEE
.Pq Dq Tn POSIX
Std 1003.1c when it is published.

View File

@ -0,0 +1,79 @@
.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. 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.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by John Birrell.
.\" 4. Neither the name of the author nor the names of any co-contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
.\"
.Dd April 4, 1996
.Dt PTHREAD_DETACH 3
.Os BSD 4
.Sh NAME
.Nm pthread_detach
.Nd detach a thread
.Sh SYNOPSIS
.Fd #include <pthread.h>
.Ft int
.Fn pthread_detach "pthread_t thread"
.Sh DESCRIPTION
The
.Fn pthread_detach
function is used to indicate to the implementation that storage for the
thread
.Fa thread
can be reclaimed when the thread terminates. If
.Fa thread
has not terminated,
.Fn pthread_detach
will not cause it to terminate. The effect of multiple
.Fn pthread_detach
calls on the same target thread is unspecified.
.Sh RETURN VALUES
If successful, the
.Fn pthread_detach
function will return zero. Otherwise an error number will be returned to
indicate the error.
.Sh ERRORS
.Fn pthread_detach
will fail if:
.Bl -tag -width Er
.It Bq Er EINVAL
The implementation has detected that the value specified by
.Fa thread
does not refer to a joinable thread.
.It Bq Er ESRCH
No thread could be found corresponding to that specified by the given
thread ID,
.Fa thread .
.El
.Pp
.Sh SEE ALSO
.Xr pthread_join 3
.Sh STANDARDS
.Fn pthread_detach
is expected to conform to IEEE
.Pq Dq Tn POSIX
Std 1003.1c when it is published.

View File

@ -0,0 +1,66 @@
.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. 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.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by John Birrell.
.\" 4. Neither the name of the author nor the names of any co-contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
.\"
.Dd April 4, 1996
.Dt PTHREAD_EQUAL 3
.Os BSD 4
.Sh NAME
.Nm pthread_equal
.Nd compare thread IDs
.Sh SYNOPSIS
.Fd #include <pthread.h>
.Ft int
.Fn pthread_equal "pthread_t t1" "pthread_t t2"
.Sh DESCRIPTION
The
.Fn pthread_equal
function compares the thread IDs
.Fa t1
and
.Fa t2 .
.Sh RETURN VALUES
The
.Fn pthread_equal
function will non-zero if the thread IDs
.Fa t1
and
.Fa t2
correspond to the same thread, otherwise it will return zero.
.Sh ERRORS
None.
.Pp
.Sh SEE ALSO
.Xr pthread_create 3 ,
.Xr pthread_exit 3
.Sh STANDARDS
.Fn pthread_equal
is expected to conform to IEEE
.Pq Dq Tn POSIX
Std 1003.1c when it is published.

View File

@ -0,0 +1,99 @@
.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. 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.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by John Birrell.
.\" 4. Neither the name of the author nor the names of any co-contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
.\"
.Dd April 4, 1996
.Dt PTHREAD_EXIT 3
.Os BSD 4
.Sh NAME
.Nm pthread_exit
.Nd terminate the calling thread
.Sh SYNOPSIS
.Fd #include <pthread.h>
.Ft void
.Fn pthread_exit "void *value_ptr"
.Sh DESCRIPTION
The
.Fn pthread_exit
function terminates the calling thread and makes the value
.Fa value_ptr
available to any successful join with the terminating thread. Any
cancellation cleanup handlers that have been pushed and are not yet popped
are popped in the reverse order that they were pushed and then executed.
After all cancellation handlers have been executed, if the thread has any
thread-specific data, appropriate destructor functions are called in an
unspecified order. Thread termination does not release any application
visible process resources, including, but not limited to, mutexes and
file descriptors, nor does it perform any process level cleanup
actions, including, but not limited to, calling
.Fn atexit
routines that may exist.
.Pp
An implicit call to
.Fn pthread_exit
is made when a thread other than the thread in which
.Fn main
was first invoked returns from the start routine that was used to create
it. The function's return value serves as the thread's exit status.
.Pp
The behavior of
.Fn pthread_exit
is undefied if called from a cancellation handler or destructor function
that was invoked as the result of an implicit or explicit call to
.Fn pthread_exit .
.Pp
After a thread has terminated, the result of access to local (auto)
variables of the thread is undefined. Thus, references to local variables
of the exiting thread should not be used for the
.Fn pthread_exit
.Fa value_ptr
parameter value.
.Pp
The process will exit with an exit status of 0 after the last thread has
been terminated. The behavior is as if the implementation called
.Fn exit
with a zero argument at thread termination time.
.Pp
.Sh RETURN VALUES
The
.Fn pthread_exit
function cannot return to its caller.
.Sh ERRORS
None.
.Pp
.Sh SEE ALSO
.Xr pthread_create 3 ,
.Xr pthread_join 3 ,
.Xr exit 2,
.Xr _exit 2
.Sh STANDARDS
.Fn pthread_exit
is expected to conform to IEEE
.Pq Dq Tn POSIX
Std 1003.1c when it is published.

View File

@ -0,0 +1,80 @@
.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. 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.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by John Birrell.
.\" 4. Neither the name of the author nor the names of any co-contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
.\"
.Dd April 4, 1996
.Dt PTHREAD_GETSPECIFIC 3
.Os BSD 4
.Sh NAME
.Nm pthread_getspecific
.Nd get a thread-specific data value
.Sh SYNOPSIS
.Fd #include <pthread.h>
.Ft void *
.Fn pthread_getspecific "pthread_key_t key"
.Sh DESCRIPTION
The
.Fn pthread_getspecific
function returns the value currently bound to the specified
.Fa key
on behalf of the calling thread.
.Pp
The effect of calling
.Fn pthread_getspecific
with a
.Fa key
value not obtained from
.Fn pthread_key_create
or after
.Fa key
has been deleted with
.Fn pthread_key_delete
is undefined.
.Pp
.Fn pthread_getspecific
may be called from a thread-specific data destructor function.
.Sh RETURN VALUES
The
.Fn pthread_getspecific
function will return the thread-specific data value associated with the given
.Fa key .
If no thread-specific data value is associated with
.Fa key ,
then the value NULL is returned.
.Sh ERRORS
None.
.Sh SEE ALSO
.Xr pthread_key_create 3 ,
.Xr pthread_key_delete 3
.Xr pthread_setspecific 3
.Sh STANDARDS
.Fn pthread_getspecific
is expected to conform to IEEE
.Pq Dq Tn POSIX
Std 1003.1c when it is published.

View File

@ -0,0 +1,100 @@
.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. 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.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by John Birrell.
.\" 4. Neither the name of the author nor the names of any co-contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
.\"
.Dd April 4, 1996
.Dt PTHREAD_JOIN 3
.Os BSD 4
.Sh NAME
.Nm pthread_join
.Nd wait for thread termination
.Sh SYNOPSIS
.Fd #include <pthread.h>
.Ft int
.Fn pthread_join "pthread_t thread" "void **value_ptr"
.Sh DESCRIPTION
The
.Fn pthread_join
function suspends execution of the calling thread until the target
.Fa thread
terminates unless the target
.Fa thread
has already terminated.
.Pp
On return from a successful
.Fn pthread_join
call with a non-NULL
.Fa value_ptr
argument, the value passed to
.Fn pthread_exit
by the terminating thread is stored in the location referenced by
.Fa value_ptr .
When a
.Fn pthread_join
returns successfully, the target thread has been terminated. The results
of multiple simultaneous calls to
.Fn pthread_join
specifying the same target thread are undefined. If the thread calling
.Fn pthread_join
is cancelled, then the target thread is not detached.
.Pp
A thread that has exited but remains unjoined counts against
[_POSIX_THREAD_THREADS_MAX].
.Pp
.Sh RETURN VALUES
If successful, the
.Fn pthread_join
function will return zero. Otherwise an error number will be returned to
indicate the error.
.Sh ERRORS
.Fn pthread_join
will fail if:
.Bl -tag -width Er
.It Bq Er EINVAL
The implementation has detected that the value specified by
.Fa thread
does not refer to a joinable thread.
.It Bq Er ESRCH
No thread could be found corresponding to that specified by the given
thread ID,
.Fa thread .
.It Bq Er EDEADLK
A deadlock was detected or the value of
.Fa thread
specifies the calling thread.
.El
.Pp
.Sh SEE ALSO
.Xr pthread_create 3 ,
.Xr wait 2
.Sh STANDARDS
.Fn pthread_join
is expected to conform to IEEE
.Pq Dq Tn POSIX
Std 1003.1c when it is published.

View File

@ -0,0 +1,98 @@
.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. 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.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by John Birrell.
.\" 4. Neither the name of the author nor the names of any co-contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
.\"
.Dd April 4, 1996
.Dt PTHREAD_KEY_CREATE 3
.Os BSD 4
.Sh NAME
.Nm pthread_key_create
.Nd thread-specific data key creation
.Sh SYNOPSIS
.Fd #include <pthread.h>
.Ft int
.Fn pthread_key_create "pthread_key_t *key" "void (*destructor)(void *)"
.Sh DESCRIPTION
The
.Fn pthread_key_create
function creates a thread-specific data key visible to all threads in the
process. Key values provided by
.Fn pthread_key_create
are opaque objects used to locate thread-specific data. Although the same
key value may be used by different threads, the values bound to the key
by
.Fn pthread_setspecific
are maintained on a per-thread basis and persist for the life of the calling
thread.
.Pp
Upon key creation, the value NULL is associated with the new key in all
active threads. Upon thread creation, the value NULL is associated with all
defined keys in the new thread.
.Pp
An optional destructor function may be associated with each key value. At
thread exit, if a key value has a non-NULL destructor pointer, and the
thread has a non-NULL value associated with the key, the function pointed
to is called with the current associated value as its sole argument. The
order of destructor calls is unspecified if more than one destructor exists
for a thread when it exits.
.Pp
If, after all the destructors have been called for all non-NULL values
with associated destructors, there are still some non-NULL values with
associated destructors, then the process is repeated. If, after at least
[PTHREAD_DESTRUCTOR_ITERATIONS] iterations of destructor calls for
outstanding non-NULL values, there are still some non-NULL values with
associated destructors, the implementation stops calling destructors.
.Sh RETURN VALUES
If successful, the
.Fn pthread_key_create
function will store the newly created key value at the location specified by
.Fa key
and returns zero. Otherwise an error number will be returned to indicate
the error.
.Sh ERRORS
.Fn pthread_key_create
will fail if:
.Bl -tag -width Er
.It Bq Er EAGAIN
The system lacked the necessary resources to create another thread-specific
data key, or the system-imposed limit on the total number of keys per process
[PTHREAD_KEYS_MAX] would be exceeded.
.It Bq Er ENOMEM
Insufficient memory exists to create the key.
.El
.Pp
.Sh SEE ALSO
.Xr pthread_getspecific 3 ,
.Xr pthread_setspecific 3 ,
.Xr pthread_key_delete 3
.Sh STANDARDS
.Fn pthread_key_create
is expected to conform to IEEE
.Pq Dq Tn POSIX
Std 1003.1c when it is published.

View File

@ -0,0 +1,92 @@
.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. 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.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by John Birrell.
.\" 4. Neither the name of the author nor the names of any co-contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
.\"
.Dd April 4, 1996
.Dt PTHREAD_KEY_DELETE 3
.Os BSD 4
.Sh NAME
.Nm pthread_key_delete
.Nd delete a thread-specific data key
.Sh SYNOPSIS
.Fd #include <pthread.h>
.Ft int
.Fn pthread_key_delete "pthread_key_t key"
.Sh DESCRIPTION
The
.Fn pthread_key_delete
function deletes a thread-specific data key previously returned by
.Fn pthread_key_create .
The thread-specific data values associated with
.Fa key
need not be NULL at the time that
.Fn pthread_key_delete
is called. It is the responsibility of the application to free any
application storage or perform any cleanup actions for data structures
related to the deleted key or associated thread-specific data in any threads;
this cleanup can be done either before or after
.Fn pthread_key_delete
is called. Any attempt to use
.Fa key
following the call to
.Fn pthread_key_delete
results in undefined behavior.
.Pp
The
.Fn pthread_key_delete
function is callable from within destructor functions. Destructor functions
are not invoked by
.Fn pthread_key_delete .
Any destructor function that may have been associated with
.Fa key
will no longer be called upon thread exit.
.Sh RETURN VALUES
If successful, the
.Fn pthread_key_delete
function will return zero. Otherwise an error number will be returned to
indicate the error.
.Sh ERRORS
.Fn pthread_key_delete
will fail if:
.Bl -tag -width Er
.It Bq Er EINVAL
The
.Fa key
value is invalid.
.El
.Pp
.Sh SEE ALSO
.Xr pthread_key_create 3 ,
.Xr pthread_getspecific 3 ,
.Xr pthread_setspecific 3
.Sh STANDARDS
.Fn pthread_key_delete
is expected to conform to IEEE
.Pq Dq Tn POSIX
Std 1003.1c when it is published.

View File

@ -0,0 +1,100 @@
.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. 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.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by John Birrell.
.\" 4. Neither the name of the author nor the names of any co-contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
.\"
.Dd April 4, 1996
.Dt PTHREAD_ONCE 3
.Os BSD 4
.Sh NAME
.Nm pthread_once
.Nd dynamic package initialization
.Sh SYNOPSIS
.Fd #include <pthread.h>
.Pp
pthread_once
.Fa once_control
= PTHREAD_ONCE_INIT;
.Ft int
.Fn pthread_once "pthread_once_t *once_control" "void *(*init_routine)(void)"
.Sh DESCRIPTION
The first call to
.Fn pthread_once
by any thread in a process, with a given
.Fa once_control ,
will call the
.Fn init_routine
with no arguments. Subsequent calls to
.Fn pthread_once
with the same
.Fa once_control
will not call the
.Fn init_routine .
On return from
.Fn pthread_once ,
it is guaranteed that
.Fn init_routine
has completed. The
.Fa once_control
parameter is used to determine whether the associated initialization
routine has been called.
.Pp
The function
.Fn pthread_once
is not a cancellation point. However, if
.Fn init_routine
is a cancellation point and is cancelled, the effect on
.Fa once_control is as if
.Fn pthread_once
was never called.
.Pp
The constant
.Fa PTHREAD_ONCE_INIT
is defined by header
.Aq Pa pthread.h .
.Pp
The behavior of
.Fn pthread_once
is undefined if
.Fa once_control
has automatic storage duration or is not initialized by
.Fa PTHREAD_ONCE_INIT .
.Pp
.Sh RETURN VALUES
If successful, the
.Fn pthread_once
function will return zero. Otherwise an error number will be returned to
indicate the error.
.Sh ERRORS
None.
.Pp
.Sh STANDARDS
.Fn pthread_once
is expected to conform to IEEE
.Pq Dq Tn POSIX
Std 1003.1c when it is published.

View File

@ -0,0 +1,59 @@
.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. 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.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by John Birrell.
.\" 4. Neither the name of the author nor the names of any co-contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
.\"
.Dd April 4, 1996
.Dt PTHREAD_SELF 3
.Os BSD 4
.Sh NAME
.Nm pthread_self
.Nd get the calling thread's ID
.Sh SYNOPSIS
.Fd #include <pthread.h>
.Ft pthread_t
.Fn pthread_self "void"
.Sh DESCRIPTION
The
.Fn pthread_self
function returns the thread ID of the calling thread.
.Sh RETURN VALUES
The
.Fn pthread_self
function returns the thread ID of the calling thread.
.Sh ERRORS
None.
.Pp
.Sh SEE ALSO
.Xr pthread_create 3 ,
.Xr pthread_equal 3
.Sh STANDARDS
.Fn pthread_self
is expected to conform to IEEE
.Pq Dq Tn POSIX
Std 1003.1c when it is published.

View File

@ -0,0 +1,91 @@
.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. 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.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by John Birrell.
.\" 4. Neither the name of the author nor the names of any co-contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
.\"
.Dd April 4, 1996
.Dt PTHREAD_SETSPECIFIC 3
.Os BSD 4
.Sh NAME
.Nm pthread_setspecific
.Nd set a thread-specific data value
.Sh SYNOPSIS
.Fd #include <pthread.h>
.Ft int
.Fn pthread_setspecific "pthread_key_t key" "const void *value"
.Sh DESCRIPTION
The
.Fn pthread_setspecific
function associates a thread-specific value with a
.Fa key
obtained via a previous call to
.Fn pthread_key_create .
Different threads man bind different values to the same key. These values are
typically pointers to blocks of dynamically allocated memory that have been
reserved for use by the calling thread.
.Pp
The effect of calling
.Fn pthread_setspecific
with a key value not obtained from
.Fn pthread_key_create
or after
.Fa key
has been deleted with
.Fn pthread_key_delete
is undefined.
.Pp
.Fn pthread_setspecific
may be called from a thread-specific data destructor function, however this
may result in lost storage or infinite loops.
.Sh RETURN VALUES
If successful, the
.Fn pthread_setspecific
function will return zero. Otherwise an error number will be returned to
indicate the error.
.Sh ERRORS
.Fn pthread_setspecific
will fail if:
.Bl -tag -width Er
.It Bq Er ENOMEM
Insufficient memory exists to associate the value with the
.Fa key .
.It Bq Er EINVAL
The
.Fa key
value is invalid.
.El
.Pp
.Sh SEE ALSO
.Xr pthread_key_create 3 ,
.Xr pthread_key_delete 3 ,
.Xr pthread_getspecific 3
.Sh STANDARDS
.Fn pthread_setspecific
is expected to conform to IEEE
.Pq Dq Tn POSIX
Std 1003.1c when it is published.

View File

@ -1,5 +1,4 @@
# @(#)Makefile.inc 8.1 (Berkeley) 6/17/93
# $Id: $
# sys sources
.PATH: ${.CURDIR}/../libc/${MACHINE}/sys ${.CURDIR}/../libc/sys \
@ -40,16 +39,18 @@ THREADASM= accept.o bind.o close.o connect.o dup.o dup2.o \
shutdown.o sigaction.o sigaltstack.o socket.o socketpair.o \
wait4.o write.o writev.o
PSEUDO= _exit.o _getlogin.o
PSEUDO= _getlogin.o
OBJS+= ${ASM} ${THREADASM} ${PSEUDO}
THREADPSEUDO= _exit.o
OBJS+= ${ASM} ${THREADASM} ${PSEUDO} ${THREADPSEUDO}
${ASM}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
@${ECHO} creating ${.PREFIX}.o
@printf '#include "SYS.h"\nRSYSCALL(${.PREFIX})\n' | \
${CPP} ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -o ${.PREFIX}.o
@${LD} -x -r ${.PREFIX}.o
@mv -f a.out ${.PREFIX}.o
@mv a.out ${.PREFIX}.o
PASM= ${ASM:.o=.po}
${PASM}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
@ -57,7 +58,7 @@ ${PASM}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
@printf '#include "SYS.h"\nRSYSCALL(${.PREFIX})\n' | \
${CPP} -DPROF ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -o ${.PREFIX}.po
@${LD} -x -r ${.PREFIX}.po
@mv -f a.out ${.PREFIX}.po
@mv a.out ${.PREFIX}.po
SASM= ${ASM:.o=.so}
${SASM}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
@ -67,23 +68,23 @@ ${SASM}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
${THREADASM}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
@${ECHO} creating ${.PREFIX}.o
@printf '#include "SYS.h"\nPRSYSCALL(${.PREFIX},_thread_sys_${.PREFIX})\n' | \
@printf '#include "SYS.h"\nPRSYSCALL(${.PREFIX})\n' | \
${CPP} ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -o ${.PREFIX}.o
@${LD} -x -r ${.PREFIX}.o
@mv -f a.out ${.PREFIX}.o
@mv a.out ${.PREFIX}.o
PTHREADASM= ${THREADASM:.o=.po}
${PTHREADASM}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
@${ECHO} creating ${.PREFIX}.po
@printf '#include "SYS.h"\nPRSYSCALL(${.PREFIX},_thread_sys_${.PREFIX})\n' | \
@printf '#include "SYS.h"\nPRSYSCALL(${.PREFIX})\n' | \
${CPP} -DPROF ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -o ${.PREFIX}.po
@${LD} -x -r ${.PREFIX}.po
@mv -f a.out ${.PREFIX}.po
@mv a.out ${.PREFIX}.po
STHREADASM= ${THREADASM:.o=.so}
${STHREADASM}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
@${ECHO} creating ${.PREFIX}.so
@printf '#include "SYS.h"\nPRSYSCALL(${.PREFIX},_thread_sys_${.PREFIX})\n' | \
@printf '#include "SYS.h"\nPRSYSCALL(${.PREFIX})\n' | \
${CPP} -DPIC ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -k -o ${.PREFIX}.so
${PSEUDO}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
@ -91,7 +92,7 @@ ${PSEUDO}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
@printf '#include "SYS.h"\nPSEUDO(${.PREFIX},${.PREFIX:S/_//})\n' | \
${CPP} ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -o ${.PREFIX}.o
@${LD} -x -r ${.PREFIX}.o
@mv -f a.out ${.PREFIX}.o
@mv a.out ${.PREFIX}.o
PPSEUDO=${PSEUDO:.o=.po}
${PPSEUDO}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
@ -99,10 +100,31 @@ ${PPSEUDO}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
@printf '#include "SYS.h"\nPSEUDO(${.PREFIX},${.PREFIX:S/_//})\n' | \
${CPP} -DPROF ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -o ${.PREFIX}.po
@${LD} -x -r ${.PREFIX}.po
@mv -f a.out ${.PREFIX}.po
@mv a.out ${.PREFIX}.po
SPSEUDO=${PSEUDO:.o=.so}
${SPSEUDO}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
@${ECHO} creating ${.PREFIX}.so
@printf '#include "SYS.h"\nPSEUDO(${.PREFIX},${.PREFIX:S/_//})\n' | \
${CPP} -DPIC ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -k -o ${.PREFIX}.so
${THREADPSEUDO}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
@${ECHO} creating ${.PREFIX}.o
@printf '#include "SYS.h"\nPPSEUDO(${.PREFIX},${.PREFIX:S/_//})\n' | \
${CPP} ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -o ${.PREFIX}.o
@${LD} -x -r ${.PREFIX}.o
@mv a.out ${.PREFIX}.o
THREADPPSEUDO=${THREADPSEUDO:.o=.po}
${THREADPPSEUDO}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
@${ECHO} creating ${.PREFIX}.po
@printf '#include "SYS.h"\nPPSEUDO(${.PREFIX},${.PREFIX:S/_//})\n' | \
${CPP} -DPROF ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -o ${.PREFIX}.po
@${LD} -x -r ${.PREFIX}.po
@mv a.out ${.PREFIX}.po
THREADSPSEUDO=${THREADPSEUDO:.o=.so}
${THREADSPSEUDO}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
@${ECHO} creating ${.PREFIX}.so
@printf '#include "SYS.h"\nPPSEUDO(${.PREFIX},${.PREFIX:S/_//})\n' | \
${CPP} -DPIC ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -k -o ${.PREFIX}.so

View File

@ -1,4 +1,4 @@
# $Id: Makefile.inc,v 1.1 1996/01/22 00:23:03 julian Exp $
# $Id: Makefile.inc,v 1.2 1996/02/17 02:19:35 jdp Exp $
CPLUSPLUSLIB= cpluspluslib
@ -7,7 +7,7 @@ CPLUSPLUSLIB= cpluspluslib
SRCS+= \
uthread_accept.c \
uthread_attr_setcreatesuspend.c \
uthread_attr_setcreatesuspend_np.c \
uthread_autoinit.cc \
uthread_bind.c \
uthread_clean.c \
@ -52,7 +52,7 @@ SRCS+= \
uthread_read.c \
uthread_readv.c \
uthread_recvfrom.c \
uthread_resume.c \
uthread_resume_np.c \
uthread_select.c \
uthread_self.c \
uthread_sendto.c \
@ -71,7 +71,7 @@ SRCS+= \
uthread_socket.c \
uthread_socketpair.c \
uthread_spec.c \
uthread_suspend.c \
uthread_suspend_np.c \
uthread_wait4.c \
uthread_write.c \
uthread_writev.c \

View File

@ -58,6 +58,129 @@
*/
#define PANIC(string) _thread_exit(__FILE__,__LINE__,string)
/*
* Queue definitions.
*/
struct pthread_queue {
struct pthread *q_next;
struct pthread *q_last;
void *q_data;
};
/*
* Static queue initialization values.
*/
#define PTHREAD_QUEUE_INITIALIZER { NULL, NULL, NULL }
/*
* Mutex definitions.
*/
enum pthread_mutextype {
MUTEX_TYPE_FAST = 1,
MUTEX_TYPE_COUNTING_FAST = 2, /* Recursive */
MUTEX_TYPE_MAX
};
union pthread_mutex_data {
void *m_ptr;
int m_count;
};
struct pthread_mutex {
enum pthread_mutextype m_type;
struct pthread_queue m_queue;
struct pthread *m_owner;
union pthread_mutex_data m_data;
long m_flags;
};
/*
* Flags for mutexes.
*/
#define MUTEX_FLAGS_PRIVATE 0x01
#define MUTEX_FLAGS_INITED 0x02
#define MUTEX_FLAGS_BUSY 0x04
/*
* Static mutex initialization values.
*/
#define PTHREAD_MUTEX_INITIALIZER \
{ MUTEX_TYPE_FAST, PTHREAD_QUEUE_INITIALIZER, \
NULL, { NULL }, MUTEX_FLAGS_INITED }
struct pthread_mutex_attr {
enum pthread_mutextype m_type;
long m_flags;
};
/*
* Condition variable definitions.
*/
enum pthread_cond_type {
COND_TYPE_FAST,
COND_TYPE_MAX
};
struct pthread_cond {
enum pthread_cond_type c_type;
struct pthread_queue c_queue;
void *c_data;
long c_flags;
};
struct pthread_cond_attr {
enum pthread_cond_type c_type;
long c_flags;
};
/*
* Flags for condition variables.
*/
#define COND_FLAGS_PRIVATE 0x01
#define COND_FLAGS_INITED 0x02
#define COND_FLAGS_BUSY 0x04
/*
* Static cond initialization values.
*/
#define PTHREAD_COND_INITIALIZER \
{ COND_TYPE_FAST, PTHREAD_QUEUE_INITIALIZER, NULL, COND_FLAGS_INITED }
/*
* Cleanup definitions.
*/
struct pthread_cleanup {
struct pthread_cleanup *next;
void (*routine) ();
void *routine_arg;
};
/*
* Scheduling definitions.
*/
enum schedparam_policy {
SCHED_RR,
SCHED_IO,
SCHED_FIFO,
SCHED_OTHER
};
struct pthread_attr {
enum schedparam_policy schedparam_policy;
int prio;
int suspend;
int flags;
void *arg_attr;
void (*cleanup_attr) ();
void *stackaddr_attr;
size_t stacksize_attr;
};
struct sched_param {
int prio;
void *no_data;
};
/*
* Thread creation state attributes.
*/
@ -67,14 +190,11 @@
/*
* Miscellaneous definitions.
*/
#define PTHREAD_STACK_MIN 1024
#define PTHREAD_STACK_DEFAULT 65536
#define PTHREAD_DATAKEYS_MAX 256
#define PTHREAD_DEFAULT_PRIORITY 64
#define PTHREAD_MAX_PRIORITY 126
#define PTHREAD_MIN_PRIORITY 0
#define _POSIX_THREAD_ATTR_STACKSIZE
#define _POSIX_THREAD_DESTRUTOR_ITERATIONS 4
/*
* Clock resolution in nanoseconds.
@ -190,10 +310,10 @@ struct pthread {
* Thread start routine, argument, stack pointer and thread
* attributes.
*/
void *(*start_routine)(void *);
void *arg;
void *stack;
pthread_attr_t attr;
void *(*start_routine)(void *);
void *arg;
void *stack;
struct pthread_attr attr;
/*
* Thread-specific signal handler interface:
@ -319,6 +439,17 @@ SCLASS struct pthread *_thread_run
;
#endif
/*
* Ptr to the thread running in single-threaded mode or NULL if
* running multi-threaded (default POSIX behaviour).
*/
SCLASS struct pthread *_thread_single
#ifdef GLOBAL_PTHREAD_PRIVATE
= NULL;
#else
;
#endif
/* Ptr to the first thread in the thread linked list: */
SCLASS struct pthread *_thread_link_list
#ifdef GLOBAL_PTHREAD_PRIVATE
@ -372,7 +503,7 @@ SCLASS struct pthread *_thread_initial
#endif
/* Default thread attributes: */
SCLASS pthread_attr_t pthread_attr_default
SCLASS struct pthread_attr pthread_attr_default
#ifdef GLOBAL_PTHREAD_PRIVATE
= { SCHED_RR, PTHREAD_DEFAULT_PRIORITY, PTHREAD_CREATE_RUNNING,
PTHREAD_CREATE_JOINABLE, NULL, NULL, NULL, PTHREAD_STACK_DEFAULT };
@ -570,6 +701,7 @@ pid_t _thread_sys_fork(void);
pid_t _thread_sys_tcgetpgrp(int);
ssize_t _thread_sys_read(int, void *, size_t);
ssize_t _thread_sys_write(int, const void *, size_t);
void _thread_sys__exit(int);
#endif
/* #include <fcntl.h> */

View File

@ -31,6 +31,7 @@
*
*/
#include <errno.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Birrell.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
*
*/
#include <stdlib.h>
#include <errno.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
#include "pthread_private.h"
int pthread_attr_destroy(pthread_attr_t *attr)
{
int ret;
if (attr == NULL || *attr == NULL) {
errno = EINVAL;
ret = -1;
} else {
free(*attr);
*attr = NULL;
ret = 0;
}
return(ret);
}
#endif

View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Birrell.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
*
*/
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
#include "pthread_private.h"
int pthread_attr_init(pthread_attr_t *attr)
{
int ret;
pthread_attr_t pattr;
if ((pattr = (pthread_attr_t) malloc(sizeof(struct pthread_attr))) == NULL) {
errno = ENOMEM;
ret = -1;
} else {
memcpy(pattr, &pthread_attr_default, sizeof(struct pthread_attr));
*attr = pattr;
ret = 0;
}
return(ret);
}
#endif

View File

@ -1,43 +0,0 @@
/*
* Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Birrell.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
*
*/
#ifdef _THREAD_SAFE
#include <pthread.h>
#include "pthread_private.h"
int
pthread_attr_setcreatesuspend(pthread_attr_t *attr)
{
attr->suspend = PTHREAD_CREATE_SUSPENDED;
return(0);
}
#endif

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Birrell.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
*
*/
#include <errno.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
#include "pthread_private.h"
int
pthread_attr_setcreatesuspend_np(pthread_attr_t *attr)
{
int ret;
if (attr == NULL || *attr == NULL) {
errno = EINVAL;
ret = -1;
} else {
(*attr)->suspend = PTHREAD_CREATE_SUSPENDED;
ret = 0;
}
return(ret);
}
#endif

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Birrell.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
*
*/
#include <errno.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
#include "pthread_private.h"
int pthread_attr_setprio(pthread_attr_t *attr, int priority)
{
int ret;
if (attr == NULL || *attr == NULL) {
errno = EINVAL;
ret = -1;
} else {
(*attr)->prio = priority;
ret = 0;
}
return(ret);
}
#endif

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Birrell.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
*
*/
#include <errno.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
#include "pthread_private.h"
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
{
int ret;
if (attr == NULL || *attr == NULL || stacksize < PTHREAD_STACK_MIN) {
errno = EINVAL;
ret = -1;
} else {
(*attr)->stacksize_attr = stacksize;
ret = 0;
}
return(ret);
}
#endif

View File

@ -30,7 +30,10 @@
* SUCH DAMAGE.
*
*/
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
#include "pthread_private.h"
@ -38,10 +41,55 @@
int
close(int fd)
{
int ret;
int flags;
int ret;
int status;
struct stat sb;
/* Lock the file descriptor while the file is closed: */
if ((ret = _thread_fd_lock(fd, FD_RDWR, NULL, __FILE__, __LINE__)) == 0) {
/* Block signals: */
_thread_kern_sig_block(&status);
/* Get file descriptor status. */
fstat(fd, &sb);
/*
* Check if the file should be left as blocking.
*
* This is so that the file descriptors shared with a parent
* process aren't left set to non-blocking if the child
* closes them prior to exit. An example where this causes
* problems with /bin/sh is when a child closes stdin.
*
* Setting a file as blocking causes problems if a threaded
* parent accesses the file descriptor before the child exits.
* Once the threaded parent receives a SIGCHLD then it resets
* all of its files to non-blocking, and so it is then safe
* to access them.
*
* Pipes are not set to blocking when they are closed, as
* the parent and child will normally close the file
* descriptor of the end of the pipe that they are not
* using, which would then cause any reads to block
* indefinitely.
*/
if ((S_ISREG(sb.st_mode) || S_ISCHR(sb.st_mode)) && (_thread_fd_table[fd]->flags & O_NONBLOCK) == 0) {
/* Get the current flags: */
flags = _thread_sys_fcntl(fd, F_GETFL, NULL);
/* Clear the nonblocking file descriptor flag: */
_thread_sys_fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
}
/* Close the file descriptor: */
ret = _thread_sys_close(fd);
_thread_fd_unlock(fd, FD_RDWR);
/* Free the file descriptor table entry: */
free(_thread_fd_table[fd]);
_thread_fd_table[fd] = NULL;
/* Unblock signals again: */
_thread_kern_sig_unblock(status);
}
return (ret);
}

View File

@ -40,41 +40,56 @@ int
pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * cond_attr)
{
enum pthread_cond_type type;
pthread_cond_t pcond;
int rval = 0;
/*
* Check if a pointer to a condition variable attribute structure was
* passed by the caller:
*/
if (cond_attr != NULL) {
/* Default to a fast condition variable: */
type = cond_attr->c_type;
} else {
/* Default to a fast condition variable: */
type = COND_TYPE_FAST;
}
/* Process according to condition variable type: */
switch (type) {
/* Fast condition variable: */
case COND_TYPE_FAST:
/* Nothing to do here. */
break;
/* Trap invalid condition variable types: */
default:
/* Return an invalid argument error: */
_thread_seterrno(_thread_run, EINVAL);
if (cond == NULL) {
errno = EINVAL;
rval = -1;
break;
}
} else {
/*
* Check if a pointer to a condition variable attribute structure was
* passed by the caller:
*/
if (cond_attr != NULL && *cond_attr != NULL) {
/* Default to a fast condition variable: */
type = (*cond_attr)->c_type;
} else {
/* Default to a fast condition variable: */
type = COND_TYPE_FAST;
}
/* Check for no errors: */
if (rval == 0) {
/* Initialise the condition variable structure: */
_thread_queue_init(&cond->c_queue);
cond->c_flags |= COND_FLAGS_INITED;
cond->c_type = type;
/* Process according to condition variable type: */
switch (type) {
/* Fast condition variable: */
case COND_TYPE_FAST:
/* Nothing to do here. */
break;
/* Trap invalid condition variable types: */
default:
/* Return an invalid argument error: */
errno = EINVAL;
rval = -1;
break;
}
/* Check for no errors: */
if (rval == 0) {
if ((pcond = (pthread_cond_t) malloc(sizeof(struct pthread_cond))) == NULL) {
errno = ENOMEM;
rval = -1;
} else {
/*
* Initialise the condition variable
* structure:
*/
_thread_queue_init(&pcond->c_queue);
pcond->c_flags |= COND_FLAGS_INITED;
pcond->c_type = type;
*cond = pcond;
}
}
}
/* Return the completion status: */
return (rval);
@ -85,26 +100,33 @@ pthread_cond_destroy(pthread_cond_t * cond)
{
int rval = 0;
/* Process according to condition variable type: */
switch (cond->c_type) {
/* Fast condition variable: */
case COND_TYPE_FAST:
/* Nothing to do here. */
break;
/* Trap invalid condition variable types: */
default:
/* Return an invalid argument error: */
_thread_seterrno(_thread_run, EINVAL);
if (cond == NULL || *cond == NULL) {
errno = EINVAL;
rval = -1;
break;
}
} else {
/* Process according to condition variable type: */
switch ((*cond)->c_type) {
/* Fast condition variable: */
case COND_TYPE_FAST:
/* Nothing to do here. */
break;
/* Check for errors: */
if (rval == 0) {
/* Destroy the contents of the condition structure: */
_thread_queue_init(&cond->c_queue);
cond->c_flags = 0;
/* Trap invalid condition variable types: */
default:
/* Return an invalid argument error: */
errno = EINVAL;
rval = -1;
break;
}
/* Check for errors: */
if (rval == 0) {
/* Destroy the contents of the condition structure: */
_thread_queue_init(&(*cond)->c_queue);
(*cond)->c_flags = 0;
free(*cond);
*cond = NULL;
}
}
/* Return the completion status: */
return (rval);
@ -116,39 +138,44 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
int rval = 0;
int status;
/* Block signals: */
_thread_kern_sig_block(&status);
/* Process according to condition variable type: */
switch (cond->c_type) {
/* Fast condition variable: */
case COND_TYPE_FAST:
/* Queue the running thread for the condition variable: */
_thread_queue_enq(&cond->c_queue, _thread_run);
/* Unlock the mutex: */
pthread_mutex_unlock(mutex);
/* Schedule the next thread: */
_thread_kern_sched_state(PS_COND_WAIT, __FILE__, __LINE__);
/* Block signals: */
_thread_kern_sig_block(NULL);
/* Lock the mutex: */
rval = pthread_mutex_lock(mutex);
break;
/* Trap invalid condition variable types: */
default:
/* Return an invalid argument error: */
_thread_seterrno(_thread_run, EINVAL);
if (cond == NULL || *cond == NULL) {
errno = EINVAL;
rval = -1;
break;
}
} else {
/* Block signals: */
_thread_kern_sig_block(&status);
/* Unblock signals: */
_thread_kern_sig_unblock(status);
/* Process according to condition variable type: */
switch ((*cond)->c_type) {
/* Fast condition variable: */
case COND_TYPE_FAST:
/* Queue the running thread for the condition variable: */
_thread_queue_enq(&(*cond)->c_queue, _thread_run);
/* Unlock the mutex: */
pthread_mutex_unlock(mutex);
/* Schedule the next thread: */
_thread_kern_sched_state(PS_COND_WAIT, __FILE__, __LINE__);
/* Block signals: */
_thread_kern_sig_block(NULL);
/* Lock the mutex: */
rval = pthread_mutex_lock(mutex);
break;
/* Trap invalid condition variable types: */
default:
/* Return an invalid argument error: */
errno = EINVAL;
rval = -1;
break;
}
/* Unblock signals: */
_thread_kern_sig_unblock(status);
}
/* Return the completion status: */
return (rval);
@ -161,59 +188,69 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
int rval = 0;
int status;
/* Block signals: */
_thread_kern_sig_block(&status);
/* Process according to condition variable type: */
switch (cond->c_type) {
/* Fast condition variable: */
case COND_TYPE_FAST:
/* Set the wakeup time: */
_thread_run->wakeup_time.ts_sec = abstime->ts_sec;
_thread_run->wakeup_time.ts_nsec = abstime->ts_nsec;
/* Reset the timeout flag: */
_thread_run->timeout = 0;
/* Queue the running thread for the condition variable: */
_thread_queue_enq(&cond->c_queue, _thread_run);
/* Unlock the mutex: */
if ((rval = pthread_mutex_unlock(mutex)) != 0) {
/*
* Cannot unlock the mutex, so remove the running
* thread from the condition variable queue:
*/
_thread_queue_deq(&cond->c_queue);
} else {
/* Schedule the next thread: */
_thread_kern_sched_state(PS_COND_WAIT, __FILE__, __LINE__);
/* Block signals: */
_thread_kern_sig_block(NULL);
/* Lock the mutex: */
if ((rval = pthread_mutex_lock(mutex)) != 0) {
}
/* Check if the wait timed out: */
else if (_thread_run->timeout) {
/* Return a timeout error: */
_thread_seterrno(_thread_run, EAGAIN);
rval = -1;
}
}
break;
/* Trap invalid condition variable types: */
default:
/* Return an invalid argument error: */
_thread_seterrno(_thread_run, EINVAL);
if (cond == NULL || *cond == NULL) {
errno = EINVAL;
rval = -1;
break;
}
} else {
/* Block signals: */
_thread_kern_sig_block(&status);
/* Unblock signals: */
_thread_kern_sig_unblock(status);
/* Process according to condition variable type: */
switch ((*cond)->c_type) {
/* Fast condition variable: */
case COND_TYPE_FAST:
/* Set the wakeup time: */
#if defined(__FreeBSD__)
_thread_run->wakeup_time.ts_sec = abstime->ts_sec;
_thread_run->wakeup_time.ts_nsec = abstime->ts_nsec;
#else
_thread_run->wakeup_time.tv_sec = abstime->tv_sec;
_thread_run->wakeup_time.tv_nsec = abstime->tv_nsec;
#endif
/* Reset the timeout flag: */
_thread_run->timeout = 0;
/* Queue the running thread for the condition variable: */
_thread_queue_enq(&(*cond)->c_queue, _thread_run);
/* Unlock the mutex: */
if ((rval = pthread_mutex_unlock(mutex)) != 0) {
/*
* Cannot unlock the mutex, so remove the running
* thread from the condition variable queue:
*/
_thread_queue_deq(&(*cond)->c_queue);
} else {
/* Schedule the next thread: */
_thread_kern_sched_state(PS_COND_WAIT, __FILE__, __LINE__);
/* Block signals: */
_thread_kern_sig_block(NULL);
/* Lock the mutex: */
if ((rval = pthread_mutex_lock(mutex)) != 0) {
}
/* Check if the wait timed out: */
else if (_thread_run->timeout) {
/* Return a timeout error: */
errno = EAGAIN;
rval = -1;
}
}
break;
/* Trap invalid condition variable types: */
default:
/* Return an invalid argument error: */
errno = EINVAL;
rval = -1;
break;
}
/* Unblock signals: */
_thread_kern_sig_unblock(status);
}
/* Return the completion status: */
return (rval);
@ -226,30 +263,35 @@ pthread_cond_signal(pthread_cond_t * cond)
int status;
pthread_t pthread;
/* Block signals: */
_thread_kern_sig_block(&status);
/* Process according to condition variable type: */
switch (cond->c_type) {
/* Fast condition variable: */
case COND_TYPE_FAST:
/* Bring the next thread off the condition queue: */
if ((pthread = _thread_queue_deq(&cond->c_queue)) != NULL) {
/* Allow the thread to run: */
pthread->state = PS_RUNNING;
}
break;
/* Trap invalid condition variable types: */
default:
/* Return an invalid argument error: */
_thread_seterrno(_thread_run, EINVAL);
if (cond == NULL || *cond == NULL) {
errno = EINVAL;
rval = -1;
break;
}
} else {
/* Block signals: */
_thread_kern_sig_block(&status);
/* Unblock signals: */
_thread_kern_sig_unblock(status);
/* Process according to condition variable type: */
switch ((*cond)->c_type) {
/* Fast condition variable: */
case COND_TYPE_FAST:
/* Bring the next thread off the condition queue: */
if ((pthread = _thread_queue_deq(&(*cond)->c_queue)) != NULL) {
/* Allow the thread to run: */
pthread->state = PS_RUNNING;
}
break;
/* Trap invalid condition variable types: */
default:
/* Return an invalid argument error: */
errno = EINVAL;
rval = -1;
break;
}
/* Unblock signals: */
_thread_kern_sig_unblock(status);
}
/* Return the completion status: */
return (rval);
@ -266,11 +308,11 @@ pthread_cond_broadcast(pthread_cond_t * cond)
_thread_kern_sig_block(&status);
/* Process according to condition variable type: */
switch (cond->c_type) {
switch ((*cond)->c_type) {
/* Fast condition variable: */
case COND_TYPE_FAST:
/* Enter a loop to bring all threads off the condition queue: */
while ((pthread = _thread_queue_deq(&cond->c_queue)) != NULL) {
while ((pthread = _thread_queue_deq(&(*cond)->c_queue)) != NULL) {
/* Allow the thread to run: */
pthread->state = PS_RUNNING;
}
@ -279,7 +321,7 @@ pthread_cond_broadcast(pthread_cond_t * cond)
/* Trap invalid condition variable types: */
default:
/* Return an invalid argument error: */
_thread_seterrno(_thread_run, EINVAL);
errno = EINVAL;
rval = -1;
break;
}

View File

@ -49,6 +49,7 @@ _thread_create(pthread_t * thread, const pthread_attr_t * attr,
int ret = 0;
int status;
pthread_t new_thread;
pthread_attr_t pattr;
void *stack;
/* Block signals: */
@ -60,15 +61,17 @@ _thread_create(pthread_t * thread, const pthread_attr_t * attr,
ret = EAGAIN;
} else {
/* Check if default thread attributes are required: */
if (attr == NULL) {
if (attr == NULL || *attr == NULL) {
/* Use the default thread attributes: */
attr = &pthread_attr_default;
pattr = &pthread_attr_default;
} else {
pattr = *attr;
}
/* Check if a stack was specified in the thread attributes: */
if ((stack = attr->stackaddr_attr) != NULL) {
if ((stack = pattr->stackaddr_attr) != NULL) {
}
/* Allocate memory for the stack: */
else if ((stack = (void *) malloc(attr->stacksize_attr)) == NULL) {
else if ((stack = (void *) malloc(pattr->stacksize_attr)) == NULL) {
/* Insufficient memory to create a thread: */
ret = EAGAIN;
free(new_thread);
@ -83,7 +86,7 @@ _thread_create(pthread_t * thread, const pthread_attr_t * attr,
new_thread->stack = stack;
new_thread->start_routine = start_routine;
new_thread->arg = arg;
if (attr->suspend == PTHREAD_CREATE_SUSPENDED) {
if (pattr->suspend == PTHREAD_CREATE_SUSPENDED) {
new_thread->state = PS_SUSPENDED;
} else {
new_thread->state = PS_RUNNING;
@ -148,19 +151,19 @@ _thread_create(pthread_t * thread, const pthread_attr_t * attr,
/* The stack starts high and builds down: */
#if defined(__FreeBSD__)
new_thread->saved_jmp_buf[0]._jb[2] = (int) (new_thread->stack + attr->stacksize_attr - sizeof(double));
new_thread->saved_jmp_buf[0]._jb[2] = (int) (new_thread->stack + pattr->stacksize_attr - sizeof(double));
#elif defined(__NetBSD__)
#if defined(__alpha)
new_thread->saved_jmp_buf[4 + R_SP] = (long) new_thread->stack + attr->stacksize_attr - sizeof(double);
new_thread->saved_jmp_buf[4 + R_SP] = (long) new_thread->stack + pattr->stacksize_attr - sizeof(double);
#else
new_thread->saved_jmp_buf[2] = (long) new_thread->stack + attr->stacksize_attr - sizeof(double);
new_thread->saved_jmp_buf[2] = (long) new_thread->stack + pattr->stacksize_attr - sizeof(double);
#endif
#else
#error "Don't recognize this operating system!"
#endif
/* Copy the thread attributes: */
memcpy(&new_thread->attr, attr, sizeof(pthread_attr_t));
memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr));
/*
* Check if this thread is to inherit the scheduling

View File

@ -31,6 +31,7 @@
*
*/
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
@ -39,15 +40,39 @@
int
execve(const char *name, char *const * argv, char *const * envp)
{
int flags;
int i;
int ret;
struct sigaction act;
struct sigaction oact;
struct itimerval itimer;
/* Disable the interval timer: */
itimer.it_interval.tv_sec = 0;
itimer.it_interval.tv_usec = 0;
itimer.it_value.tv_sec = 0;
itimer.it_value.tv_usec = 0;
setitimer(ITIMER_VIRTUAL, &itimer, NULL);
/* Close the pthread kernel pipe: */
_thread_sys_close(_thread_kern_pipe[0]);
_thread_sys_close(_thread_kern_pipe[1]);
/*
* Enter a loop to set all file descriptors to blocking
* if they were not created as non-blocking:
*/
for (i = 0; i < _thread_dtablesize; i++) {
/* Check if this file descriptor is in use: */
if (_thread_fd_table[i] != NULL &&
!(_thread_fd_table[i]->flags & O_NONBLOCK)) {
/* Get the current flags: */
flags = _thread_sys_fcntl(i, F_GETFL, NULL);
/* Clear the nonblocking file descriptor flag: */
_thread_sys_fcntl(i, F_SETFL, flags & ~O_NONBLOCK);
}
}
/* Enter a loop to adopt the signal actions for the running thread: */
for (i = 1; i < NSIG; i++) {
/* Check for signals which cannot be caught: */

View File

@ -31,11 +31,49 @@
*
*/
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
#include "pthread_private.h"
void _exit(int status)
{
int flags;
int i;
struct itimerval itimer;
/* Disable the interval timer: */
itimer.it_interval.tv_sec = 0;
itimer.it_interval.tv_usec = 0;
itimer.it_value.tv_sec = 0;
itimer.it_value.tv_usec = 0;
setitimer(ITIMER_VIRTUAL, &itimer, NULL);
/* Close the pthread kernel pipe: */
_thread_sys_close(_thread_kern_pipe[0]);
_thread_sys_close(_thread_kern_pipe[1]);
/*
* Enter a loop to set all file descriptors to blocking
* if they were not created as non-blocking:
*/
for (i = 0; i < _thread_dtablesize; i++) {
/* Check if this file descriptor is in use: */
if (_thread_fd_table[i] != NULL &&
!(_thread_fd_table[i]->flags & O_NONBLOCK)) {
/* Get the current flags: */
flags = _thread_sys_fcntl(i, F_GETFL, NULL);
/* Clear the nonblocking file descriptor flag: */
_thread_sys_fcntl(i, F_SETFL, flags & ~O_NONBLOCK);
}
}
/* Call the _exit syscall: */
_thread_sys__exit(status);
}
void
_thread_exit(char *fname, int lineno, char *string)
{

View File

@ -31,6 +31,7 @@
*
*/
#include <stdarg.h>
#include <unistd.h>
#include <fcntl.h>
#ifdef _THREAD_SAFE
#include <pthread.h>

View File

@ -31,6 +31,7 @@
*
*/
#include <errno.h>
#include <fcntl.h>
#include <stdlib.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
@ -48,7 +49,7 @@ _thread_fd_table_init(int fd)
/* Check if the file descriptor is out of range: */
if (fd < 0 || fd >= _thread_dtablesize) {
/* Return a bad file descriptor error: */
_thread_seterrno(_thread_run, EBADF);
errno = EBADF;
ret = -1;
}
/*
@ -60,7 +61,7 @@ _thread_fd_table_init(int fd)
/* Allocate memory for the file descriptor table entry: */
else if ((_thread_fd_table[fd] = (struct fd_table_entry *) malloc(sizeof(struct fd_table_entry))) == NULL) {
/* Return a bad file descriptor error: */
_thread_seterrno(_thread_run, EBADF);
errno = EBADF;
ret = -1;
} else {
/* Initialise the file locks: */
@ -73,12 +74,25 @@ _thread_fd_table_init(int fd)
_thread_fd_table[fd]->r_lockcount = 0;;
_thread_fd_table[fd]->w_lockcount = 0;;
/* Default the flags: */
_thread_fd_table[fd]->flags = 0;
/* Initialise the read/write queues: */
_thread_queue_init(&_thread_fd_table[fd]->r_queue);
_thread_queue_init(&_thread_fd_table[fd]->w_queue);
/* Get the flags for the file: */
if ((_thread_fd_table[fd]->flags = _thread_sys_fcntl(fd, F_GETFL, 0)) == -1) {
ret = -1;
/* Make the file descriptor non-blocking: */
} else {
_thread_sys_fcntl(fd, F_SETFL, _thread_fd_table[fd]->flags | O_NONBLOCK);
}
/* Check if one of the fcntl calls failed: */
if (ret == -1) {
/* Free the file descriptor table entry: */
free(_thread_fd_table[fd]);
_thread_fd_table[fd] = NULL;
}
}
/* Unblock signals: */

View File

@ -31,6 +31,8 @@
*
*/
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#ifdef _THREAD_SAFE
#include <pthread.h>

View File

@ -202,18 +202,6 @@ _thread_main(int argc, char *argv[], char *env)
_thread_init();
return (main(argc, argv, env));
}
#else
/*
* Force our auto-initialization module to be pulled in from the library,
* by referencing a symbol that is defined in it.
*
* The auto-initialization module is a small C++ module. It has a static
* constructor that calls _thread_init() automatically, at the beginning
* of program execution. That eliminates the need for any special hooks
* in crt0.o.
*/
extern int _thread_autoinit_dummy_decl;
static int *_thread_autoinit_dummy_ref = &_thread_autoinit_dummy_decl;
#endif
#else
/*

View File

@ -250,18 +250,30 @@ __asm__("fnsave %0": :"m"(*fdata));
pthread->state == PS_FDW_WAIT ||
pthread->state == PS_SELECT_WAIT) {
/* Check if this thread is to wait forever: */
#if defined(__FreeBSD__)
if (pthread->wakeup_time.ts_sec == -1) {
#else
if (pthread->wakeup_time.tv_sec == -1) {
#endif
}
/*
* Check if this thread is to wakeup
* immediately or if it is past its wakeup
* time:
*/
#if defined(__FreeBSD__)
else if ((pthread->wakeup_time.ts_sec == 0 &&
pthread->wakeup_time.ts_nsec == 0) ||
(ts.ts_sec > pthread->wakeup_time.ts_sec) ||
((ts.ts_sec == pthread->wakeup_time.ts_sec) &&
(ts.ts_nsec >= pthread->wakeup_time.ts_nsec))) {
#else
else if ((pthread->wakeup_time.tv_sec == 0 &&
pthread->wakeup_time.tv_nsec == 0) ||
(ts.tv_sec > pthread->wakeup_time.tv_sec) ||
((ts.tv_sec == pthread->wakeup_time.tv_sec) &&
(ts.tv_nsec >= pthread->wakeup_time.tv_nsec))) {
#endif
/*
* Check if this thread is waiting on
* select:
@ -364,9 +376,48 @@ __asm__("fnsave %0": :"m"(*fdata));
}
/*
* Enter a loop to look for the first thread of the highest
* priority:
* priority that is ready to run:
*/
for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) {
/* Check if in single-threaded mode: */
if (_thread_single != NULL) {
/*
* Check if the current thread is
* the thread for which single-threaded
* mode is enabled:
*/
if (pthread == _thread_single) {
/*
* This thread is allowed
* to run.
*/
} else {
/*
* Walk up the signal handler
* parent thread tree to see
* if the current thread is
* descended from the thread
* for which single-threaded
* mode is enabled.
*/
pthread_nxt = pthread;
while(pthread_nxt != NULL &&
pthread_nxt != _thread_single) {
pthread_nxt = pthread->parent_thread;
}
/*
* Check if the current
* thread is not descended
* from the thread for which
* single-threaded mode is
* enabled.
*/
if (pthread_nxt == NULL)
/* Ignore this thread. */
continue;
}
}
/* Check if the current thread is unable to run: */
if (pthread->state != PS_RUNNING) {
}
@ -392,6 +443,45 @@ __asm__("fnsave %0": :"m"(*fdata));
* least recently.
*/
for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) {
/* Check if in single-threaded mode: */
if (_thread_single != NULL) {
/*
* Check if the current thread is
* the thread for which single-threaded
* mode is enabled:
*/
if (pthread == _thread_single) {
/*
* This thread is allowed
* to run.
*/
} else {
/*
* Walk up the signal handler
* parent thread tree to see
* if the current thread is
* descended from the thread
* for which single-threaded
* mode is enabled.
*/
pthread_nxt = pthread;
while(pthread_nxt != NULL &&
pthread_nxt != _thread_single) {
pthread_nxt = pthread->parent_thread;
}
/*
* Check if the current
* thread is not descended
* from the thread for which
* single-threaded mode is
* enabled.
*/
if (pthread_nxt == NULL)
/* Ignore this thread. */
continue;
}
}
/* Check if the current thread is unable to run: */
if (pthread->state != PS_RUNNING) {
/* Ignore threads that are not ready to run. */
@ -446,6 +536,45 @@ __asm__("fnsave %0": :"m"(*fdata));
* priority. 3. Became inactive least recently.
*/
for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) {
/* Check if in single-threaded mode: */
if (_thread_single != NULL) {
/*
* Check if the current thread is
* the thread for which single-threaded
* mode is enabled:
*/
if (pthread == _thread_single) {
/*
* This thread is allowed
* to run.
*/
} else {
/*
* Walk up the signal handler
* parent thread tree to see
* if the current thread is
* descended from the thread
* for which single-threaded
* mode is enabled.
*/
pthread_nxt = pthread;
while(pthread_nxt != NULL &&
pthread_nxt != _thread_single) {
pthread_nxt = pthread->parent_thread;
}
/*
* Check if the current
* thread is not descended
* from the thread for which
* single-threaded mode is
* enabled.
*/
if (pthread_nxt == NULL)
/* Ignore this thread. */
continue;
}
}
/*
* Check if the current thread is unable to
* run:
@ -565,22 +694,37 @@ __asm__("fnsave %0": :"m"(*fdata));
* Check if this thread is to
* wait forever:
*/
#if defined(__FreeBSD__)
if (pthread->wakeup_time.ts_sec == -1) {
#else
if (pthread->wakeup_time.tv_sec == -1) {
#endif
}
/*
* Check if this thread is to
* wakeup immediately:
*/
#if defined(__FreeBSD__)
else if (pthread->wakeup_time.ts_sec == 0 &&
pthread->wakeup_time.ts_nsec == 0) {
#else
else if (pthread->wakeup_time.tv_sec == 0 &&
pthread->wakeup_time.tv_nsec == 0) {
#endif
}
/*
* Check if the current time
* is after the wakeup time:
*/
#if defined(__FreeBSD__)
else if ((ts.ts_sec > pthread->wakeup_time.ts_sec) ||
((ts.ts_sec == pthread->wakeup_time.ts_sec) &&
(ts.ts_nsec > pthread->wakeup_time.ts_nsec))) {
#else
else if ((ts.tv_sec > pthread->wakeup_time.tv_sec) ||
((ts.tv_sec == pthread->wakeup_time.tv_sec) &&
(ts.tv_nsec > pthread->wakeup_time.tv_nsec))) {
#endif
} else {
/*
* Calculate the time
@ -589,16 +733,26 @@ __asm__("fnsave %0": :"m"(*fdata));
* for the clock
* resolution:
*/
#if defined(__FreeBSD__)
ts1.ts_sec = pthread->wakeup_time.ts_sec - ts.ts_sec;
ts1.ts_nsec = pthread->wakeup_time.ts_nsec - ts.ts_nsec +
CLOCK_RES_NSEC;
#else
ts1.tv_sec = pthread->wakeup_time.tv_sec - ts.tv_sec;
ts1.tv_nsec = pthread->wakeup_time.tv_nsec - ts.tv_nsec +
CLOCK_RES_NSEC;
#endif
/*
* Check for
* underflow of the
* nanosecond field:
*/
#if defined(__FreeBSD__)
if (ts1.ts_nsec < 0) {
#else
if (ts1.tv_nsec < 0) {
#endif
/*
* Allow for
* the
@ -607,15 +761,24 @@ __asm__("fnsave %0": :"m"(*fdata));
* nanosecond
* field:
*/
#if defined(__FreeBSD__)
ts1.ts_sec--;
ts1.ts_nsec += 1000000000;
#else
ts1.tv_sec--;
ts1.tv_nsec += 1000000000;
#endif
}
/*
* Check for overflow
* of the nanosecond
* field:
*/
#if defined(__FreeBSD__)
if (ts1.ts_nsec >= 1000000000) {
#else
if (ts1.tv_nsec >= 1000000000) {
#endif
/*
* Allow for
* the
@ -624,8 +787,13 @@ __asm__("fnsave %0": :"m"(*fdata));
* nanosecond
* field:
*/
#if defined(__FreeBSD__)
ts1.ts_sec++;
ts1.ts_nsec -= 1000000000;
#else
ts1.tv_sec++;
ts1.tv_nsec -= 1000000000;
#endif
}
/*
* Convert the
@ -1100,11 +1268,20 @@ _thread_kern_select(int wait_reqd)
*/
if (wait_reqd && settimeout) {
/* Check if this thread wants to wait forever: */
#if defined(__FreeBSD__)
if (pthread->wakeup_time.ts_sec == -1) {
#else
if (pthread->wakeup_time.tv_sec == -1) {
#endif
}
/* Check if this thread doesn't want to wait at all: */
#if defined(__FreeBSD__)
else if (pthread->wakeup_time.ts_sec == 0 &&
pthread->wakeup_time.ts_nsec == 0) {
#else
else if (pthread->wakeup_time.tv_sec == 0 &&
pthread->wakeup_time.tv_nsec == 0) {
#endif
/* Override the caller's request to wait: */
wait_reqd = 0;
} else {
@ -1112,33 +1289,57 @@ _thread_kern_select(int wait_reqd)
* Calculate the time until this thread is
* ready, allowing for the clock resolution:
*/
#if defined(__FreeBSD__)
ts1.ts_sec = pthread->wakeup_time.ts_sec - ts.ts_sec;
ts1.ts_nsec = pthread->wakeup_time.ts_nsec - ts.ts_nsec +
CLOCK_RES_NSEC;
#else
ts1.tv_sec = pthread->wakeup_time.tv_sec - ts.tv_sec;
ts1.tv_nsec = pthread->wakeup_time.tv_nsec - ts.tv_nsec +
CLOCK_RES_NSEC;
#endif
/*
* Check for underflow of the nanosecond
* field:
*/
#if defined(__FreeBSD__)
if (ts1.ts_nsec < 0) {
#else
if (ts1.tv_nsec < 0) {
#endif
/*
* Allow for the underflow of the
* nanosecond field:
*/
#if defined(__FreeBSD__)
ts1.ts_sec--;
ts1.ts_nsec += 1000000000;
#else
ts1.tv_sec--;
ts1.tv_nsec += 1000000000;
#endif
}
/*
* Check for overflow of the nanosecond
* field:
*/
#if defined(__FreeBSD__)
if (ts1.ts_nsec >= 1000000000) {
#else
if (ts1.tv_nsec >= 1000000000) {
#endif
/*
* Allow for the overflow of the
* nanosecond field:
*/
#if defined(__FreeBSD__)
ts1.ts_sec++;
ts1.ts_nsec -= 1000000000;
#else
ts1.tv_sec++;
ts1.tv_nsec -= 1000000000;
#endif
}
/*
* Convert the timespec structure to a
@ -1552,28 +1753,56 @@ _thread_kern_set_timeout(struct timespec * timeout)
* Set the wakeup time to something that can be recognised as
* different to an actual time of day:
*/
#if defined(__FreeBSD__)
_thread_run->wakeup_time.ts_sec = -1;
_thread_run->wakeup_time.ts_nsec = -1;
#else
_thread_run->wakeup_time.tv_sec = -1;
_thread_run->wakeup_time.tv_nsec = -1;
#endif
}
/* Check if no waiting is required: */
#if defined(__FreeBSD__)
else if (timeout->ts_sec == 0 && timeout->ts_nsec == 0) {
#else
else if (timeout->tv_sec == 0 && timeout->tv_nsec == 0) {
#endif
/* Set the wake up time to 'immediately': */
#if defined(__FreeBSD__)
_thread_run->wakeup_time.ts_sec = 0;
_thread_run->wakeup_time.ts_nsec = 0;
#else
_thread_run->wakeup_time.tv_sec = 0;
_thread_run->wakeup_time.tv_nsec = 0;
#endif
} else {
/* Get the current time: */
gettimeofday(&tv, NULL);
TIMEVAL_TO_TIMESPEC(&tv, &current_time);
/* Calculate the time for the current thread to wake up: */
#if defined(__FreeBSD__)
_thread_run->wakeup_time.ts_sec = current_time.ts_sec + timeout->ts_sec;
_thread_run->wakeup_time.ts_nsec = current_time.ts_nsec + timeout->ts_nsec;
#else
_thread_run->wakeup_time.tv_sec = current_time.tv_sec + timeout->tv_sec;
_thread_run->wakeup_time.tv_nsec = current_time.tv_nsec + timeout->tv_nsec;
#endif
/* Check if the nanosecond field needs to wrap: */
#if defined(__FreeBSD__)
if (_thread_run->wakeup_time.ts_nsec >= 1000000000) {
#else
if (_thread_run->wakeup_time.tv_nsec >= 1000000000) {
#endif
/* Wrap the nanosecond field: */
#if defined(__FreeBSD__)
_thread_run->wakeup_time.ts_sec += 1;
_thread_run->wakeup_time.ts_nsec -= 1000000000;
#else
_thread_run->wakeup_time.tv_sec += 1;
_thread_run->wakeup_time.tv_nsec -= 1000000000;
#endif
}
}
return;

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Birrell.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
*
*/
#include <string.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
#include "pthread_private.h"
int pthread_multi_np()
{
/* Return to multi-threaded scheduling mode: */
_thread_single = NULL;
return(0);
}
#endif

View File

@ -41,62 +41,75 @@ pthread_mutex_init(pthread_mutex_t * mutex,
const pthread_mutexattr_t * mutex_attr)
{
enum pthread_mutextype type;
pthread_mutex_t pmutex;
int ret = 0;
int status;
/* Check if the mutex attributes specify some mutex other than fast: */
if (mutex_attr != NULL && mutex_attr->m_type != MUTEX_TYPE_FAST) {
/* Check if the mutex type is out of range: */
if (mutex_attr->m_type >= MUTEX_TYPE_MAX) {
if (mutex == NULL) {
errno = EINVAL;
ret = -1;
} else {
/* Check if default mutex attributes: */
if (mutex_attr == NULL || *mutex_attr == NULL) {
/* Default to a fast mutex: */
type = MUTEX_TYPE_FAST;
} else if ((*mutex_attr)->m_type >= MUTEX_TYPE_MAX) {
/* Return an invalid argument error: */
_thread_seterrno(_thread_run, EINVAL);
errno = EINVAL;
ret = -1;
} else {
/* Use the requested mutex type: */
type = mutex_attr->m_type;
}
} else {
/* Default to a fast mutex: */
type = MUTEX_TYPE_FAST;
}
/* Check no errors so far: */
if (ret == 0) {
/* Reset the mutex flags: */
mutex->m_flags = 0;
/* Block signals: */
_thread_kern_sig_block(&status);
/* Process according to mutex type: */
switch (type) {
/* Fast mutex: */
case MUTEX_TYPE_FAST:
/* Nothing to do here. */
break;
/* Counting mutex: */
case MUTEX_TYPE_COUNTING_FAST:
/* Reset the mutex count: */
mutex->m_data.m_count = 0;
break;
/* Trap invalid mutex types: */
default:
/* Return an invalid argument error: */
_thread_seterrno(_thread_run, EINVAL);
ret = -1;
break;
type = (*mutex_attr)->m_type;
}
/* Initialise the rest of the mutex: */
_thread_queue_init(&mutex->m_queue);
mutex->m_flags |= MUTEX_FLAGS_INITED;
mutex->m_owner = NULL;
mutex->m_type = type;
/* Check no errors so far: */
if (ret == 0) {
if ((pmutex = (pthread_mutex_t) malloc(sizeof(struct pthread_mutex))) == NULL) {
errno = ENOMEM;
ret = -1;
} else {
/* Reset the mutex flags: */
pmutex->m_flags = 0;
/* Unblock signals: */
_thread_kern_sig_unblock(status);
/* Block signals: */
_thread_kern_sig_block(&status);
/* Process according to mutex type: */
switch (type) {
/* Fast mutex: */
case MUTEX_TYPE_FAST:
/* Nothing to do here. */
break;
/* Counting mutex: */
case MUTEX_TYPE_COUNTING_FAST:
/* Reset the mutex count: */
pmutex->m_data.m_count = 0;
break;
/* Trap invalid mutex types: */
default:
/* Return an invalid argument error: */
errno = EINVAL;
ret = -1;
break;
}
if (ret == 0) {
/* Initialise the rest of the mutex: */
_thread_queue_init(&pmutex->m_queue);
pmutex->m_flags |= MUTEX_FLAGS_INITED;
pmutex->m_owner = NULL;
pmutex->m_type = type;
*mutex = pmutex;
} else {
free(pmutex);
*mutex = NULL;
}
/* Unblock signals: */
_thread_kern_sig_unblock(status);
}
}
}
/* Return the completion status: */
return (ret);
@ -108,38 +121,43 @@ pthread_mutex_destroy(pthread_mutex_t * mutex)
int ret = 0;
int status;
/* Block signals: */
_thread_kern_sig_block(&status);
/* Process according to mutex type: */
switch (mutex->m_type) {
/* Fast mutex: */
case MUTEX_TYPE_FAST:
/* Nothing to do here. */
break;
/* Counting mutex: */
case MUTEX_TYPE_COUNTING_FAST:
/* Reset the mutex count: */
mutex->m_data.m_count = 0;
break;
/* Trap undefined mutex types: */
default:
/* Return an invalid argument error: */
_thread_seterrno(_thread_run, EINVAL);
if (mutex == NULL || *mutex == NULL) {
errno = EINVAL;
ret = -1;
break;
} else {
/* Block signals: */
_thread_kern_sig_block(&status);
/* Process according to mutex type: */
switch ((*mutex)->m_type) {
/* Fast mutex: */
case MUTEX_TYPE_FAST:
/* Nothing to do here. */
break;
/* Counting mutex: */
case MUTEX_TYPE_COUNTING_FAST:
/* Reset the mutex count: */
(*mutex)->m_data.m_count = 0;
break;
/* Trap undefined mutex types: */
default:
/* Return an invalid argument error: */
errno = EINVAL;
ret = -1;
break;
}
/* Clean up the mutex in case that others want to use it: */
_thread_queue_init(&(*mutex)->m_queue);
(*mutex)->m_owner = NULL;
(*mutex)->m_flags = 0;
/* Unblock signals: */
_thread_kern_sig_unblock(status);
}
/* Clean up the mutex in case that others want to use it: */
_thread_queue_init(&mutex->m_queue);
mutex->m_owner = NULL;
mutex->m_flags = 0;
/* Unblock signals: */
_thread_kern_sig_unblock(status);
/* Return the completion status: */
return (ret);
}
@ -150,56 +168,61 @@ pthread_mutex_trylock(pthread_mutex_t * mutex)
int ret = 0;
int status;
/* Block signals: */
_thread_kern_sig_block(&status);
if (mutex == NULL || *mutex == NULL) {
errno = EINVAL;
ret = -1;
} else {
/* Block signals: */
_thread_kern_sig_block(&status);
/* Process according to mutex type: */
switch (mutex->m_type) {
/* Process according to mutex type: */
switch ((*mutex)->m_type) {
/* Fast mutex: */
case MUTEX_TYPE_FAST:
/* Check if this mutex is not locked: */
if (mutex->m_owner == NULL) {
/* Lock the mutex for the running thread: */
mutex->m_owner = _thread_run;
} else {
/* Return a busy error: */
_thread_seterrno(_thread_run, EBUSY);
ret = -1;
}
break;
/* Counting mutex: */
case MUTEX_TYPE_COUNTING_FAST:
/* Check if this mutex is locked: */
if (mutex->m_owner != NULL) {
/*
* Check if the mutex is locked by the running
* thread:
*/
if (mutex->m_owner == _thread_run) {
/* Increment the lock count: */
mutex->m_data.m_count++;
case MUTEX_TYPE_FAST:
/* Check if this mutex is not locked: */
if ((*mutex)->m_owner == NULL) {
/* Lock the mutex for the running thread: */
(*mutex)->m_owner = _thread_run;
} else {
/* Return a busy error: */
_thread_seterrno(_thread_run, EBUSY);
errno = EBUSY;
ret = -1;
}
} else {
/* Lock the mutex for the running thread: */
mutex->m_owner = _thread_run;
}
break;
break;
/* Counting mutex: */
case MUTEX_TYPE_COUNTING_FAST:
/* Check if this mutex is locked: */
if ((*mutex)->m_owner != NULL) {
/*
* Check if the mutex is locked by the running
* thread:
*/
if ((*mutex)->m_owner == _thread_run) {
/* Increment the lock count: */
(*mutex)->m_data.m_count++;
} else {
/* Return a busy error: */
errno = EBUSY;
ret = -1;
}
} else {
/* Lock the mutex for the running thread: */
(*mutex)->m_owner = _thread_run;
}
break;
/* Trap invalid mutex types: */
default:
/* Return an invalid argument error: */
_thread_seterrno(_thread_run, EINVAL);
ret = -1;
break;
}
default:
/* Return an invalid argument error: */
errno = EINVAL;
ret = -1;
break;
}
/* Unblock signals: */
_thread_kern_sig_unblock(status);
/* Unblock signals: */
_thread_kern_sig_unblock(status);
}
/* Return the completion status: */
return (ret);
@ -211,81 +234,86 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
int ret = 0;
int status;
/* Block signals: */
_thread_kern_sig_block(&status);
if (mutex == NULL || *mutex == NULL) {
errno = EINVAL;
ret = -1;
} else {
/* Block signals: */
_thread_kern_sig_block(&status);
/* Process according to mutex type: */
switch (mutex->m_type) {
/* Process according to mutex type: */
switch ((*mutex)->m_type) {
/* Fast mutexes do not check for any error conditions: */
case MUTEX_TYPE_FAST:
/*
* Enter a loop to wait for the mutex to be locked by the
* current thread:
*/
while (mutex->m_owner != _thread_run) {
/* Check if the mutex is not locked: */
if (mutex->m_owner == NULL) {
/* Lock the mutex for this thread: */
mutex->m_owner = _thread_run;
} else {
/*
* Join the queue of threads waiting to lock
* the mutex:
*/
_thread_queue_enq(&mutex->m_queue, _thread_run);
case MUTEX_TYPE_FAST:
/*
* Enter a loop to wait for the mutex to be locked by the
* current thread:
*/
while ((*mutex)->m_owner != _thread_run) {
/* Check if the mutex is not locked: */
if ((*mutex)->m_owner == NULL) {
/* Lock the mutex for this thread: */
(*mutex)->m_owner = _thread_run;
} else {
/*
* Join the queue of threads waiting to lock
* the mutex:
*/
_thread_queue_enq(&(*mutex)->m_queue, _thread_run);
/* Block signals: */
_thread_kern_sched_state(PS_MUTEX_WAIT, __FILE__, __LINE__);
/* Block signals: */
_thread_kern_sched_state(PS_MUTEX_WAIT, __FILE__, __LINE__);
/* Block signals: */
_thread_kern_sig_block(NULL);
/* Block signals: */
_thread_kern_sig_block(NULL);
}
}
}
break;
break;
/* Counting mutex: */
case MUTEX_TYPE_COUNTING_FAST:
/*
* Enter a loop to wait for the mutex to be locked by the
* current thread:
*/
while (mutex->m_owner != _thread_run) {
/* Check if the mutex is not locked: */
if (mutex->m_owner == NULL) {
/* Lock the mutex for this thread: */
mutex->m_owner = _thread_run;
case MUTEX_TYPE_COUNTING_FAST:
/*
* Enter a loop to wait for the mutex to be locked by the
* current thread:
*/
while ((*mutex)->m_owner != _thread_run) {
/* Check if the mutex is not locked: */
if ((*mutex)->m_owner == NULL) {
/* Lock the mutex for this thread: */
(*mutex)->m_owner = _thread_run;
/* Reset the lock count for this mutex: */
mutex->m_data.m_count = 0;
} else {
/*
* Join the queue of threads waiting to lock
* the mutex:
*/
_thread_queue_enq(&mutex->m_queue, _thread_run);
/* Reset the lock count for this mutex: */
(*mutex)->m_data.m_count = 0;
} else {
/*
* Join the queue of threads waiting to lock
* the mutex:
*/
_thread_queue_enq(&(*mutex)->m_queue, _thread_run);
/* Block signals: */
_thread_kern_sched_state(PS_MUTEX_WAIT, __FILE__, __LINE__);
/* Block signals: */
_thread_kern_sched_state(PS_MUTEX_WAIT, __FILE__, __LINE__);
/* Block signals: */
_thread_kern_sig_block(NULL);
/* Block signals: */
_thread_kern_sig_block(NULL);
}
}
}
/* Increment the lock count for this mutex: */
mutex->m_data.m_count++;
break;
/* Increment the lock count for this mutex: */
(*mutex)->m_data.m_count++;
break;
/* Trap invalid mutex types: */
default:
/* Return an invalid argument error: */
_thread_seterrno(_thread_run, EINVAL);
ret = -1;
break;
}
default:
/* Return an invalid argument error: */
errno = EINVAL;
ret = -1;
break;
}
/* Unblock signals: */
_thread_kern_sig_unblock(status);
/* Unblock signals: */
_thread_kern_sig_unblock(status);
}
/* Return the completion status: */
return (ret);
@ -297,62 +325,67 @@ pthread_mutex_unlock(pthread_mutex_t * mutex)
int ret = 0;
int status;
/* Block signals: */
_thread_kern_sig_block(&status);
if (mutex == NULL || *mutex == NULL) {
errno = EINVAL;
ret = -1;
} else {
/* Block signals: */
_thread_kern_sig_block(&status);
/* Process according to mutex type: */
switch (mutex->m_type) {
/* Process according to mutex type: */
switch ((*mutex)->m_type) {
/* Fast mutexes do not check for any error conditions: */
case MUTEX_TYPE_FAST:
/* Check if the running thread is not the owner of the mutex: */
if (mutex->m_owner != _thread_run) {
/* Return an invalid argument error: */
_thread_seterrno(_thread_run, EINVAL);
ret = -1;
}
/*
* Get the next thread from the queue of threads waiting on
* the mutex:
*/
else if ((mutex->m_owner = _thread_queue_deq(&mutex->m_queue)) != NULL) {
/* Allow the new owner of the mutex to run: */
mutex->m_owner->state = PS_RUNNING;
}
break;
case MUTEX_TYPE_FAST:
/* Check if the running thread is not the owner of the mutex: */
if ((*mutex)->m_owner != _thread_run) {
/* Return an invalid argument error: */
errno = EINVAL;
ret = -1;
}
/*
* Get the next thread from the queue of threads waiting on
* the mutex:
*/
else if (((*mutex)->m_owner = _thread_queue_deq(&(*mutex)->m_queue)) != NULL) {
/* Allow the new owner of the mutex to run: */
(*mutex)->m_owner->state = PS_RUNNING;
}
break;
/* Counting mutex: */
case MUTEX_TYPE_COUNTING_FAST:
/* Check if the running thread is not the owner of the mutex: */
if (mutex->m_owner != _thread_run) {
/* Return an invalid argument error: */
_thread_seterrno(_thread_run, EINVAL);
ret = -1;
}
/* Check if there are still counts: */
else if (mutex->m_data.m_count) {
/* Decrement the count: */
mutex->m_data.m_count--;
}
/*
* Get the next thread from the queue of threads waiting on
* the mutex:
*/
else if ((mutex->m_owner = _thread_queue_deq(&mutex->m_queue)) != NULL) {
/* Allow the new owner of the mutex to run: */
mutex->m_owner->state = PS_RUNNING;
}
break;
case MUTEX_TYPE_COUNTING_FAST:
/* Check if the running thread is not the owner of the mutex: */
if ((*mutex)->m_owner != _thread_run) {
/* Return an invalid argument error: */
errno = EINVAL;
ret = -1;
}
/* Check if there are still counts: */
else if ((*mutex)->m_data.m_count) {
/* Decrement the count: */
(*mutex)->m_data.m_count--;
}
/*
* Get the next thread from the queue of threads waiting on
* the mutex:
*/
else if (((*mutex)->m_owner = _thread_queue_deq(&(*mutex)->m_queue)) != NULL) {
/* Allow the new owner of the mutex to run: */
(*mutex)->m_owner->state = PS_RUNNING;
}
break;
/* Trap invalid mutex types: */
default:
/* Return an invalid argument error: */
_thread_seterrno(_thread_run, EINVAL);
ret = -1;
break;
}
default:
/* Return an invalid argument error: */
errno = EINVAL;
ret = -1;
break;
}
/* Unblock signals: */
_thread_kern_sig_unblock(status);
/* Unblock signals: */
_thread_kern_sig_unblock(status);
}
/* Return the completion status: */
return (ret);

View File

@ -31,6 +31,7 @@
*
*/
#include <stdio.h>
#include <errno.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
#include "pthread_private.h"
@ -38,50 +39,138 @@
int
nanosleep(struct timespec * time_to_sleep, struct timespec * time_remaining)
{
int ret = 0;
struct timespec current_time;
struct timespec current_time1;
struct timespec remaining_time;
struct timeval tv;
/* Get the current time: */
gettimeofday(&tv, NULL);
TIMEVAL_TO_TIMESPEC(&tv, &current_time);
/* Check if the time to sleep is legal: */
#if defined(__FreeBSD__)
if (time_to_sleep == NULL || time_to_sleep->ts_nsec < 0 || time_to_sleep->ts_nsec > 1000000000) {
#else
if (time_to_sleep == NULL || time_to_sleep->tv_nsec < 0 || time_to_sleep->tv_nsec > 1000000000) {
#endif
/* Return an EINVAL error : */
errno = EINVAL;
ret = -1;
} else {
/* Get the current time: */
gettimeofday(&tv, NULL);
TIMEVAL_TO_TIMESPEC(&tv, &current_time);
/* Calculate the time for the current thread to wake up: */
_thread_run->wakeup_time.ts_sec = current_time.ts_sec + time_to_sleep->ts_sec;
_thread_run->wakeup_time.ts_nsec = current_time.ts_nsec + time_to_sleep->ts_nsec;
/* Calculate the time for the current thread to wake up: */
#if defined(__FreeBSD__)
_thread_run->wakeup_time.ts_sec = current_time.ts_sec + time_to_sleep->ts_sec;
_thread_run->wakeup_time.ts_nsec = current_time.ts_nsec + time_to_sleep->ts_nsec;
#else
_thread_run->wakeup_time.tv_sec = current_time.tv_sec + time_to_sleep->tv_sec;
_thread_run->wakeup_time.tv_nsec = current_time.tv_nsec + time_to_sleep->tv_nsec;
#endif
/* Check if the nanosecond field has overflowed: */
if (_thread_run->wakeup_time.ts_nsec >= 1000000000) {
/* Wrap the nanosecond field: */
_thread_run->wakeup_time.ts_sec += 1;
_thread_run->wakeup_time.ts_nsec -= 1000000000;
}
/* Reschedule the current thread to sleep: */
_thread_kern_sched_state(PS_SLEEP_WAIT, __FILE__, __LINE__);
/* Check if the nanosecond field has overflowed: */
#if defined(__FreeBSD__)
if (_thread_run->wakeup_time.ts_nsec >= 1000000000) {
#else
if (_thread_run->wakeup_time.tv_nsec >= 1000000000) {
#endif
/* Wrap the nanosecond field: */
#if defined(__FreeBSD__)
_thread_run->wakeup_time.ts_sec += 1;
_thread_run->wakeup_time.ts_nsec -= 1000000000;
#else
_thread_run->wakeup_time.tv_sec += 1;
_thread_run->wakeup_time.tv_nsec -= 1000000000;
#endif
}
/* Reschedule the current thread to sleep: */
_thread_kern_sched_state(PS_SLEEP_WAIT, __FILE__, __LINE__);
/* Check if the time remaining is to be returned: */
if (time_remaining != NULL) {
/* Get the current time: */
gettimeofday(&tv, NULL);
TIMEVAL_TO_TIMESPEC(&tv, &current_time1);
/* Return the actual time slept: */
time_remaining->ts_sec = time_to_sleep->ts_sec + current_time1.ts_sec - current_time.ts_sec;
time_remaining->ts_nsec = time_to_sleep->ts_nsec + current_time1.ts_nsec - current_time.ts_nsec;
/* Calculate the remaining time to sleep: */
#if defined(__FreeBSD__)
remaining_time.ts_sec = time_to_sleep->ts_sec + current_time.ts_sec - current_time1.ts_sec;
remaining_time.ts_nsec = time_to_sleep->ts_nsec + current_time.ts_nsec - current_time1.ts_nsec;
#else
remaining_time.tv_sec = time_to_sleep->tv_sec + current_time.tv_sec - current_time1.tv_sec;
remaining_time.tv_nsec = time_to_sleep->tv_nsec + current_time.tv_nsec - current_time1.tv_nsec;
#endif
/* Check if the nanosecond field has underflowed: */
if (time_remaining->ts_nsec < 0) {
#if defined(__FreeBSD__)
if (remaining_time.ts_nsec < 0) {
#else
if (remaining_time.tv_nsec < 0) {
#endif
/* Handle the underflow: */
time_remaining->ts_sec -= 1;
time_remaining->ts_nsec += 1000000000;
#if defined(__FreeBSD__)
remaining_time.ts_sec -= 1;
remaining_time.ts_nsec += 1000000000;
#else
remaining_time.tv_sec -= 1;
remaining_time.tv_nsec += 1000000000;
#endif
}
/* Check if the nanosecond field has overflowed: */
#if defined(__FreeBSD__)
if (remaining_time.ts_nsec >= 1000000000) {
#else
if (remaining_time.tv_nsec >= 1000000000) {
#endif
/* Handle the overflow: */
#if defined(__FreeBSD__)
remaining_time.ts_sec += 1;
remaining_time.ts_nsec -= 1000000000;
#else
remaining_time.tv_sec += 1;
remaining_time.tv_nsec -= 1000000000;
#endif
}
/* Check if the sleep was longer than the required time: */
if (time_remaining->ts_sec < 0) {
/* Reset the time teft: */
time_remaining->ts_sec = 0;
time_remaining->ts_nsec = 0;
#if defined(__FreeBSD__)
if (remaining_time.ts_sec < 0) {
#else
if (remaining_time.tv_sec < 0) {
#endif
/* Reset the time left: */
#if defined(__FreeBSD__)
remaining_time.ts_sec = 0;
remaining_time.ts_nsec = 0;
#else
remaining_time.tv_sec = 0;
remaining_time.tv_nsec = 0;
#endif
}
/* Check if the time remaining is to be returned: */
if (time_remaining != NULL) {
/* Return the actual time slept: */
#if defined(__FreeBSD__)
time_remaining->ts_sec = remaining_time.ts_sec;
time_remaining->ts_nsec = remaining_time.ts_nsec;
#else
time_remaining->tv_sec = remaining_time.tv_sec;
time_remaining->tv_nsec = remaining_time.tv_nsec;
#endif
}
/* Check if the entire sleep was not completed: */
#if defined(__FreeBSD__)
if (remaining_time.ts_nsec != 0 || remaining_time.ts_sec != 0) {
#else
if (remaining_time.tv_nsec != 0 || remaining_time.tv_sec != 0) {
#endif
/* Return an EINTR error : */
errno = EINTR;
ret = -1;
}
}
return (0);
return (ret);
}
#endif

View File

@ -31,6 +31,7 @@
*
*/
#include <stdarg.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#ifdef _THREAD_SAFE
@ -55,8 +56,8 @@ open(const char *path, int flags,...)
mode = va_arg(ap, int);
va_end(ap);
}
/* Open the file, forcing it to use non-blocking I/O operations: */
if ((fd = _thread_sys_open(path, flags | O_NONBLOCK, mode)) < 0) {
/* Open the file: */
if ((fd = _thread_sys_open(path, flags, mode)) < 0) {
}
/* Initialise the file descriptor table entry: */
else if (_thread_fd_table_init(fd) != 0) {
@ -65,12 +66,6 @@ open(const char *path, int flags,...)
/* Reset the file descriptor: */
fd = -1;
} else {
/*
* Save the file open flags so that they can be checked
* later:
*/
_thread_fd_table[fd]->flags = flags;
}
/* Unblock signals: */

View File

@ -46,11 +46,6 @@ pipe(int fds[2])
_thread_sys_close(fds[0]);
_thread_sys_close(fds[1]);
ret = -1;
} else {
_thread_fd_table[fds[0]]->flags = _thread_sys_fcntl(fds[0], F_GETFL, NULL);
_thread_sys_fcntl(fds[0], F_SETFL, _thread_fd_table[fds[0]]->flags | O_NONBLOCK);
_thread_fd_table[fds[1]]->flags = _thread_sys_fcntl(fds[1], F_GETFL, NULL);
_thread_sys_fcntl(fds[1], F_SETFL, _thread_fd_table[fds[1]]->flags | O_NONBLOCK);
}
}
return (ret);

View File

@ -1,70 +0,0 @@
/*
* Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Birrell.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
*
*/
#include <errno.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
#include "pthread_private.h"
int
pthread_resume(pthread_t thread)
{
int ret = -1;
pthread_t pthread;
/*
* Search for the thread in the linked list.
*/
for (pthread = _thread_link_list; pthread != NULL && ret == -1; pthread = pthread->nxt) {
/* Is this the thread? */
if (pthread == thread) {
/* Found the thread. Is it suspended? */
if (pthread->state == PS_SUSPENDED) {
/* Allow the thread to run. */
pthread->state = PS_RUNNING;
ret = 0;
} else if (pthread->state == PS_RUNNING) {
/* Thread is already running. */
ret = 0;
} else {
/* Thread is in some other state. */
_thread_seterrno(_thread_run,EINVAL);
}
}
}
/* Check if thread was not found. */
if (ret == -1) {
/* No such thread */
_thread_seterrno(_thread_run,ESRCH);
}
return(ret);
}
#endif

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Birrell.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
*
*/
#include <errno.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
#include "pthread_private.h"
int
pthread_resume_np(pthread_t thread)
{
int ret = -1;
pthread_t pthread;
/*
* Search for the thread in the linked list.
*/
for (pthread = _thread_link_list; pthread != NULL && ret == -1; pthread = pthread->nxt) {
/* Is this the thread? */
if (pthread == thread) {
/* Found the thread. Is it suspended? */
if (pthread->state == PS_SUSPENDED) {
/* Allow the thread to run. */
pthread->state = PS_RUNNING;
ret = 0;
} else if (pthread->state == PS_RUNNING) {
/* Thread is already running. */
ret = 0;
} else {
/* Thread is in some other state. */
_thread_seterrno(_thread_run,EINVAL);
}
}
}
/* Check if thread was not found. */
if (ret == -1) {
/* No such thread */
_thread_seterrno(_thread_run,ESRCH);
}
return(ret);
}
#endif

View File

@ -142,36 +142,29 @@ select(int numfds, fd_set * readfds, fd_set * writefds,
if (ret > 0) {
if (readfds != NULL) {
FD_ZERO(readfds);
for (i = 0; i < numfds; i++) {
if (FD_ISSET(i, &data.readfds)) {
FD_SET(i, readfds);
if (FD_ISSET(i, readfds) &&
!FD_ISSET(i, &data.readfds)) {
FD_CLR(i, readfds);
}
}
}
if (writefds != NULL) {
FD_ZERO(writefds);
for (i = 0; i < numfds; i++) {
if (FD_ISSET(i, &data.writefds)) {
FD_SET(i, writefds);
if (FD_ISSET(i, writefds) &&
!FD_ISSET(i, &data.writefds)) {
FD_CLR(i, writefds);
}
}
}
if (exceptfds != NULL) {
FD_ZERO(exceptfds);
for (i = 0; i < numfds; i++) {
if (FD_ISSET(i, &data.exceptfds)) {
FD_SET(i, exceptfds);
if (FD_ISSET(i, exceptfds) &&
!FD_ISSET(i, &data.exceptfds)) {
FD_CLR(i, exceptfds);
}
}
}
} else {
if (exceptfds != NULL)
FD_ZERO(exceptfds);
if (writefds != NULL)
FD_ZERO(writefds);
if (readfds != NULL)
FD_ZERO(readfds);
}
return (ret);

View File

@ -31,6 +31,8 @@
*
*/
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
@ -40,6 +42,7 @@ void
_thread_sig_handler(int sig, int code, struct sigcontext * scp)
{
char c;
int i;
pthread_t pthread;
/*
@ -67,16 +70,52 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp)
} else {
/* Handle depending on signal type: */
switch (sig) {
/* Interval timer used for timeslicing: */
/* Interval timer used for timeslicing: */
case SIGVTALRM:
/*
* Don't add the signal to any thread. Just want to
* call
* call the scheduler:
*/
/* the scheduler: */
break;
/* Signals specific to the running thread: */
/* Child termination: */
case SIGCHLD:
/*
* Enter a loop to process each thread in the linked
* list:
*/
for (pthread = _thread_link_list; pthread != NULL;
pthread = pthread->nxt) {
/*
* Add the signal to the set of pending
* signals:
*/
pthread->sigpend[sig] += 1;
if (pthread->state == PS_WAIT_WAIT) {
/* Reset the error: */
/* There should be another flag so that this is not required! ### */
_thread_seterrno(pthread, 0);
/* Change the state of the thread to run: */
pthread->state = PS_RUNNING;
}
}
/*
* Go through the file list and set all files
* to non-blocking again in case the child
* set some of them to block. Sigh.
*/
for (i = 0; i < _thread_dtablesize; i++) {
/* Check if this file is used: */
if (_thread_fd_table[i] != NULL) {
/* Set the file descriptor to non-blocking: */
_thread_sys_fcntl(i, F_SETFL, _thread_fd_table[i]->flags | O_NONBLOCK);
}
}
break;
/* Signals specific to the running thread: */
case SIGBUS:
case SIGEMT:
case SIGFPE:
@ -88,7 +127,7 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp)
_thread_run->sigpend[sig] += 1;
break;
/* Signals to send to all threads: */
/* Signals to send to all threads: */
default:
/*
* Enter a loop to process each thread in the linked

View File

@ -47,6 +47,9 @@ sigsuspend(const sigset_t * set)
/* Save the current sigmal mask: */
oset = _thread_run->sigmask;
/* Combine the caller's mask with the current one: */
_thread_run->sigmask |= *set;
/* Wait for a signal: */
_thread_kern_sched_state(PS_SIGWAIT, __FILE__, __LINE__);

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Birrell.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
*
*/
#include <string.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
#include "pthread_private.h"
int pthread_single_np()
{
/* Enter single-threaded (non-POSIX) scheduling mode: */
_thread_single = _thread_run;
return(0);
}
#endif

View File

@ -33,6 +33,7 @@
#include <sys/types.h>
#include <sys/socket.h>
#include <fcntl.h>
#include <unistd.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
#include "pthread_private.h"
@ -40,17 +41,16 @@
int
socket(int af, int type, int protocol)
{
int fd;
int tmp_flags;
int fd;
/* Create a socket: */
if ((fd = _thread_sys_socket(af, type, protocol)) < 0) {
/* Error creating socket. */
/* Initialise the entry in the file descriptor table: */
} else if (_thread_fd_table_init(fd) != 0) {
_thread_sys_close(fd);
fd = -1;
} else {
tmp_flags = _thread_sys_fcntl(fd, F_GETFL, 0);
_thread_sys_fcntl(fd, F_SETFL, tmp_flags | O_NONBLOCK);
_thread_fd_table[fd]->flags = tmp_flags;
}
return (fd);
}

View File

@ -39,12 +39,12 @@
#include "pthread_private.h"
/* Static variables: */
static struct pthread_key key_table[PTHREAD_DATAKEYS_MAX];
static struct pthread_key key_table[PTHREAD_KEYS_MAX];
int
pthread_keycreate(pthread_key_t * key, void (*destructor) (void *))
pthread_key_create(pthread_key_t * key, void (*destructor) (void *))
{
for ((*key) = 0; (*key) < PTHREAD_DATAKEYS_MAX; (*key)++) {
for ((*key) = 0; (*key) < PTHREAD_KEYS_MAX; (*key)++) {
if (key_table[(*key)].count == 0) {
key_table[(*key)].count++;
key_table[(*key)].destructor = destructor;
@ -63,7 +63,7 @@ pthread_key_delete(pthread_key_t key)
/* Block signals: */
_thread_kern_sig_block(&status);
if (key < PTHREAD_DATAKEYS_MAX) {
if (key < PTHREAD_KEYS_MAX) {
switch (key_table[key].count) {
case 1:
key_table[key].destructor = NULL;
@ -94,8 +94,8 @@ _thread_cleanupspecific(void)
/* Block signals: */
_thread_kern_sig_block(&status);
for (itr = 0; itr < _POSIX_THREAD_DESTRUTOR_ITERATIONS; itr++) {
for (key = 0; key < PTHREAD_DATAKEYS_MAX; key++) {
for (itr = 0; itr < PTHREAD_DESTRUCTOR_ITERATIONS; itr++) {
for (key = 0; key < PTHREAD_KEYS_MAX; key++) {
if (_thread_run->specific_data_count) {
if (_thread_run->specific_data[key]) {
data = (void *) _thread_run->specific_data[key];
@ -125,8 +125,8 @@ static inline const void **
pthread_key_allocate_data(void)
{
const void **new_data;
if ((new_data = (const void **) malloc(sizeof(void *) * PTHREAD_DATAKEYS_MAX)) != NULL) {
memset((void *) new_data, 0, sizeof(void *) * PTHREAD_DATAKEYS_MAX);
if ((new_data = (const void **) malloc(sizeof(void *) * PTHREAD_KEYS_MAX)) != NULL) {
memset((void *) new_data, 0, sizeof(void *) * PTHREAD_KEYS_MAX);
}
return (new_data);
}
@ -154,7 +154,7 @@ pthread_setspecific(pthread_key_t key, const void *value)
}
if ((pthread->specific_data) || (pthread->specific_data = pthread_key_allocate_data())) {
if ((key < PTHREAD_DATAKEYS_MAX) && (key_table)) {
if ((key < PTHREAD_KEYS_MAX) && (key_table)) {
if (key_table[key].count) {
if (pthread->specific_data[key] == NULL) {
if (value != NULL) {
@ -213,7 +213,7 @@ pthread_getspecific(pthread_key_t key, void **p_data)
rval = -1;
}
/* Check if there is specific data: */
else if (pthread->specific_data != NULL && (key < PTHREAD_DATAKEYS_MAX) && (key_table)) {
else if (pthread->specific_data != NULL && (key < PTHREAD_KEYS_MAX) && (key_table)) {
/* Check if this key has been used before: */
if (key_table[key].count) {
/* Return the value: */

View File

@ -1,67 +0,0 @@
/*
* Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Birrell.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
*
*/
#include <errno.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
#include "pthread_private.h"
int
pthread_suspend(pthread_t thread)
{
int ret = -1;
pthread_t pthread;
/*
* Search for the thread in the linked list.
*/
for (pthread = _thread_link_list; pthread != NULL && ret == -1; pthread = pthread->nxt) {
/* Is this the thread? */
if (pthread == thread) {
/* Found the thread. Is it running? */
if (pthread->state != PS_RUNNING &&
pthread->state != PS_SUSPENDED) {
/* The thread operation has been interrupted */
_thread_seterrno(pthread,EINTR);
}
/* Suspend the thread. */
pthread->state = PS_SUSPENDED;
ret = 0;
}
}
/* Check if thread was not found. */
if (ret == -1) {
/* No such thread */
_thread_seterrno(_thread_run,ESRCH);
}
return(ret);
}
#endif

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Birrell.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
*
*/
#include <errno.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
#include "pthread_private.h"
int
pthread_suspend_np(pthread_t thread)
{
int ret = -1;
pthread_t pthread;
/*
* Search for the thread in the linked list.
*/
for (pthread = _thread_link_list; pthread != NULL && ret == -1; pthread = pthread->nxt) {
/* Is this the thread? */
if (pthread == thread) {
/* Found the thread. Is it running? */
if (pthread->state != PS_RUNNING &&
pthread->state != PS_SUSPENDED) {
/* The thread operation has been interrupted */
_thread_seterrno(pthread,EINTR);
}
/* Suspend the thread. */
pthread->state = PS_SUSPENDED;
ret = 0;
}
}
/* Check if thread was not found. */
if (ret == -1) {
/* No such thread */
_thread_seterrno(_thread_run,ESRCH);
}
return(ret);
}
#endif

View File

@ -20,6 +20,7 @@ PRECIOUSLIB= yes
.include "${.CURDIR}/gen/Makefile.inc"
.include "${.CURDIR}/gmon/Makefile.inc"
.include "${.CURDIR}/locale/Makefile.inc"
.include "${.CURDIR}/man/Makefile.inc"
.include "${.CURDIR}/net/Makefile.inc"
.include "${.CURDIR}/nls/Makefile.inc"
.include "${.CURDIR}/quad/Makefile.inc"
@ -38,24 +39,8 @@ CFLAGS+= -DYP
.endif
.include "${.CURDIR}/${MACHINE}/sys/Makefile.inc"
KQSRCS= adddi3.c anddi3.c ashldi3.c ashrdi3.c cmpdi2.c divdi3.c iordi3.c \
lshldi3.c lshrdi3.c moddi3.c muldi3.c negdi2.c notdi2.c qdivrem.c \
subdi3.c ucmpdi2.c udivdi3.c umoddi3.c xordi3.c
KSRCS= bcmp.c ffs.c index.c mcount.c rindex.c strcat.c strcmp.c strcpy.c \
strlen.c strncpy.c
libkern: libkern.gen libkern.${MACHINE}
libkern.gen: ${KQSRCS} ${KSRCS}
cp -p ${.CURDIR}/quad/quad.h ${.ALLSRC} /sys/libkern
libkern.${MACHINE}:: ${KMSRCS}
.if defined(KMSRCS) && !empty(KMSRCS)
cp -p ${.ALLSRC} /sys/libkern/${MACHINE}
.endif
#beforeinstall: tags
# ${INSTALL} ${COPY} -o bin -g bin -m 444 tags /var/db/libc.tags
beforeinstall: tags
${INSTALL} ${COPY} -o bin -g bin -m 444 tags /var/db/libc_r.tags
tags: ${SRCS}
ctags ${.ALLSRC:M*.c}

View File

@ -1,5 +1,4 @@
# @(#)Makefile.inc 8.1 (Berkeley) 6/17/93
# $Id: $
# sys sources
.PATH: ${.CURDIR}/../libc/${MACHINE}/sys ${.CURDIR}/../libc/sys \
@ -40,16 +39,18 @@ THREADASM= accept.o bind.o close.o connect.o dup.o dup2.o \
shutdown.o sigaction.o sigaltstack.o socket.o socketpair.o \
wait4.o write.o writev.o
PSEUDO= _exit.o _getlogin.o
PSEUDO= _getlogin.o
OBJS+= ${ASM} ${THREADASM} ${PSEUDO}
THREADPSEUDO= _exit.o
OBJS+= ${ASM} ${THREADASM} ${PSEUDO} ${THREADPSEUDO}
${ASM}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
@${ECHO} creating ${.PREFIX}.o
@printf '#include "SYS.h"\nRSYSCALL(${.PREFIX})\n' | \
${CPP} ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -o ${.PREFIX}.o
@${LD} -x -r ${.PREFIX}.o
@mv -f a.out ${.PREFIX}.o
@mv a.out ${.PREFIX}.o
PASM= ${ASM:.o=.po}
${PASM}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
@ -57,7 +58,7 @@ ${PASM}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
@printf '#include "SYS.h"\nRSYSCALL(${.PREFIX})\n' | \
${CPP} -DPROF ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -o ${.PREFIX}.po
@${LD} -x -r ${.PREFIX}.po
@mv -f a.out ${.PREFIX}.po
@mv a.out ${.PREFIX}.po
SASM= ${ASM:.o=.so}
${SASM}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
@ -67,23 +68,23 @@ ${SASM}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
${THREADASM}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
@${ECHO} creating ${.PREFIX}.o
@printf '#include "SYS.h"\nPRSYSCALL(${.PREFIX},_thread_sys_${.PREFIX})\n' | \
@printf '#include "SYS.h"\nPRSYSCALL(${.PREFIX})\n' | \
${CPP} ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -o ${.PREFIX}.o
@${LD} -x -r ${.PREFIX}.o
@mv -f a.out ${.PREFIX}.o
@mv a.out ${.PREFIX}.o
PTHREADASM= ${THREADASM:.o=.po}
${PTHREADASM}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
@${ECHO} creating ${.PREFIX}.po
@printf '#include "SYS.h"\nPRSYSCALL(${.PREFIX},_thread_sys_${.PREFIX})\n' | \
@printf '#include "SYS.h"\nPRSYSCALL(${.PREFIX})\n' | \
${CPP} -DPROF ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -o ${.PREFIX}.po
@${LD} -x -r ${.PREFIX}.po
@mv -f a.out ${.PREFIX}.po
@mv a.out ${.PREFIX}.po
STHREADASM= ${THREADASM:.o=.so}
${STHREADASM}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
@${ECHO} creating ${.PREFIX}.so
@printf '#include "SYS.h"\nPRSYSCALL(${.PREFIX},_thread_sys_${.PREFIX})\n' | \
@printf '#include "SYS.h"\nPRSYSCALL(${.PREFIX})\n' | \
${CPP} -DPIC ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -k -o ${.PREFIX}.so
${PSEUDO}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
@ -91,7 +92,7 @@ ${PSEUDO}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
@printf '#include "SYS.h"\nPSEUDO(${.PREFIX},${.PREFIX:S/_//})\n' | \
${CPP} ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -o ${.PREFIX}.o
@${LD} -x -r ${.PREFIX}.o
@mv -f a.out ${.PREFIX}.o
@mv a.out ${.PREFIX}.o
PPSEUDO=${PSEUDO:.o=.po}
${PPSEUDO}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
@ -99,10 +100,31 @@ ${PPSEUDO}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
@printf '#include "SYS.h"\nPSEUDO(${.PREFIX},${.PREFIX:S/_//})\n' | \
${CPP} -DPROF ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -o ${.PREFIX}.po
@${LD} -x -r ${.PREFIX}.po
@mv -f a.out ${.PREFIX}.po
@mv a.out ${.PREFIX}.po
SPSEUDO=${PSEUDO:.o=.so}
${SPSEUDO}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
@${ECHO} creating ${.PREFIX}.so
@printf '#include "SYS.h"\nPSEUDO(${.PREFIX},${.PREFIX:S/_//})\n' | \
${CPP} -DPIC ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -k -o ${.PREFIX}.so
${THREADPSEUDO}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
@${ECHO} creating ${.PREFIX}.o
@printf '#include "SYS.h"\nPPSEUDO(${.PREFIX},${.PREFIX:S/_//})\n' | \
${CPP} ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -o ${.PREFIX}.o
@${LD} -x -r ${.PREFIX}.o
@mv a.out ${.PREFIX}.o
THREADPPSEUDO=${THREADPSEUDO:.o=.po}
${THREADPPSEUDO}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
@${ECHO} creating ${.PREFIX}.po
@printf '#include "SYS.h"\nPPSEUDO(${.PREFIX},${.PREFIX:S/_//})\n' | \
${CPP} -DPROF ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -o ${.PREFIX}.po
@${LD} -x -r ${.PREFIX}.po
@mv a.out ${.PREFIX}.po
THREADSPSEUDO=${THREADPSEUDO:.o=.so}
${THREADSPSEUDO}: ${.CURDIR}/../libc/${MACHINE}/SYS.h /usr/include/sys/syscall.h
@${ECHO} creating ${.PREFIX}.so
@printf '#include "SYS.h"\nPPSEUDO(${.PREFIX},${.PREFIX:S/_//})\n' | \
${CPP} -DPIC ${CFLAGS:M-[ID]*} ${AINC} | ${AS} -k -o ${.PREFIX}.so

View File

@ -1,4 +1,4 @@
# $Id: Makefile.inc,v 1.1 1996/01/22 00:23:03 julian Exp $
# $Id: Makefile.inc,v 1.2 1996/02/17 02:19:35 jdp Exp $
CPLUSPLUSLIB= cpluspluslib
@ -7,7 +7,7 @@ CPLUSPLUSLIB= cpluspluslib
SRCS+= \
uthread_accept.c \
uthread_attr_setcreatesuspend.c \
uthread_attr_setcreatesuspend_np.c \
uthread_autoinit.cc \
uthread_bind.c \
uthread_clean.c \
@ -52,7 +52,7 @@ SRCS+= \
uthread_read.c \
uthread_readv.c \
uthread_recvfrom.c \
uthread_resume.c \
uthread_resume_np.c \
uthread_select.c \
uthread_self.c \
uthread_sendto.c \
@ -71,7 +71,7 @@ SRCS+= \
uthread_socket.c \
uthread_socketpair.c \
uthread_spec.c \
uthread_suspend.c \
uthread_suspend_np.c \
uthread_wait4.c \
uthread_write.c \
uthread_writev.c \

View File

@ -0,0 +1,52 @@
/*
* Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Birrell.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
*
*/
#include <stdlib.h>
#include <errno.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
#include "pthread_private.h"
int pthread_attr_destroy(pthread_attr_t *attr)
{
int ret;
if (attr == NULL || *attr == NULL) {
errno = EINVAL;
ret = -1;
} else {
free(*attr);
*attr = NULL;
ret = 0;
}
return(ret);
}
#endif

View File

@ -0,0 +1,54 @@
/*
* Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Birrell.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
*
*/
#include <string.h>
#include <stdlib.h>
#include <errno.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
#include "pthread_private.h"
int pthread_attr_init(pthread_attr_t *attr)
{
int ret;
pthread_attr_t pattr;
if ((pattr = (pthread_attr_t) malloc(sizeof(struct pthread_attr))) == NULL) {
errno = ENOMEM;
ret = -1;
} else {
memcpy(pattr, &pthread_attr_default, sizeof(struct pthread_attr));
*attr = pattr;
ret = 0;
}
return(ret);
}
#endif

View File

@ -0,0 +1,51 @@
/*
* Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Birrell.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
*
*/
#include <errno.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
#include "pthread_private.h"
int
pthread_attr_setcreatesuspend_np(pthread_attr_t *attr)
{
int ret;
if (attr == NULL || *attr == NULL) {
errno = EINVAL;
ret = -1;
} else {
(*attr)->suspend = PTHREAD_CREATE_SUSPENDED;
ret = 0;
}
return(ret);
}
#endif

View File

@ -0,0 +1,50 @@
/*
* Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Birrell.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
*
*/
#include <errno.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
#include "pthread_private.h"
int pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize)
{
int ret;
if (attr == NULL || *attr == NULL || stacksize < PTHREAD_STACK_MIN) {
errno = EINVAL;
ret = -1;
} else {
(*attr)->stacksize_attr = stacksize;
ret = 0;
}
return(ret);
}
#endif

View File

@ -30,7 +30,10 @@
* SUCH DAMAGE.
*
*/
#include <stdlib.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/stat.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
#include "pthread_private.h"
@ -38,10 +41,55 @@
int
close(int fd)
{
int ret;
int flags;
int ret;
int status;
struct stat sb;
/* Lock the file descriptor while the file is closed: */
if ((ret = _thread_fd_lock(fd, FD_RDWR, NULL, __FILE__, __LINE__)) == 0) {
/* Block signals: */
_thread_kern_sig_block(&status);
/* Get file descriptor status. */
fstat(fd, &sb);
/*
* Check if the file should be left as blocking.
*
* This is so that the file descriptors shared with a parent
* process aren't left set to non-blocking if the child
* closes them prior to exit. An example where this causes
* problems with /bin/sh is when a child closes stdin.
*
* Setting a file as blocking causes problems if a threaded
* parent accesses the file descriptor before the child exits.
* Once the threaded parent receives a SIGCHLD then it resets
* all of its files to non-blocking, and so it is then safe
* to access them.
*
* Pipes are not set to blocking when they are closed, as
* the parent and child will normally close the file
* descriptor of the end of the pipe that they are not
* using, which would then cause any reads to block
* indefinitely.
*/
if ((S_ISREG(sb.st_mode) || S_ISCHR(sb.st_mode)) && (_thread_fd_table[fd]->flags & O_NONBLOCK) == 0) {
/* Get the current flags: */
flags = _thread_sys_fcntl(fd, F_GETFL, NULL);
/* Clear the nonblocking file descriptor flag: */
_thread_sys_fcntl(fd, F_SETFL, flags & ~O_NONBLOCK);
}
/* Close the file descriptor: */
ret = _thread_sys_close(fd);
_thread_fd_unlock(fd, FD_RDWR);
/* Free the file descriptor table entry: */
free(_thread_fd_table[fd]);
_thread_fd_table[fd] = NULL;
/* Unblock signals again: */
_thread_kern_sig_unblock(status);
}
return (ret);
}

View File

@ -40,41 +40,56 @@ int
pthread_cond_init(pthread_cond_t * cond, const pthread_condattr_t * cond_attr)
{
enum pthread_cond_type type;
pthread_cond_t pcond;
int rval = 0;
/*
* Check if a pointer to a condition variable attribute structure was
* passed by the caller:
*/
if (cond_attr != NULL) {
/* Default to a fast condition variable: */
type = cond_attr->c_type;
} else {
/* Default to a fast condition variable: */
type = COND_TYPE_FAST;
}
/* Process according to condition variable type: */
switch (type) {
/* Fast condition variable: */
case COND_TYPE_FAST:
/* Nothing to do here. */
break;
/* Trap invalid condition variable types: */
default:
/* Return an invalid argument error: */
_thread_seterrno(_thread_run, EINVAL);
if (cond == NULL) {
errno = EINVAL;
rval = -1;
break;
}
} else {
/*
* Check if a pointer to a condition variable attribute structure was
* passed by the caller:
*/
if (cond_attr != NULL && *cond_attr != NULL) {
/* Default to a fast condition variable: */
type = (*cond_attr)->c_type;
} else {
/* Default to a fast condition variable: */
type = COND_TYPE_FAST;
}
/* Check for no errors: */
if (rval == 0) {
/* Initialise the condition variable structure: */
_thread_queue_init(&cond->c_queue);
cond->c_flags |= COND_FLAGS_INITED;
cond->c_type = type;
/* Process according to condition variable type: */
switch (type) {
/* Fast condition variable: */
case COND_TYPE_FAST:
/* Nothing to do here. */
break;
/* Trap invalid condition variable types: */
default:
/* Return an invalid argument error: */
errno = EINVAL;
rval = -1;
break;
}
/* Check for no errors: */
if (rval == 0) {
if ((pcond = (pthread_cond_t) malloc(sizeof(struct pthread_cond))) == NULL) {
errno = ENOMEM;
rval = -1;
} else {
/*
* Initialise the condition variable
* structure:
*/
_thread_queue_init(&pcond->c_queue);
pcond->c_flags |= COND_FLAGS_INITED;
pcond->c_type = type;
*cond = pcond;
}
}
}
/* Return the completion status: */
return (rval);
@ -85,26 +100,33 @@ pthread_cond_destroy(pthread_cond_t * cond)
{
int rval = 0;
/* Process according to condition variable type: */
switch (cond->c_type) {
/* Fast condition variable: */
case COND_TYPE_FAST:
/* Nothing to do here. */
break;
/* Trap invalid condition variable types: */
default:
/* Return an invalid argument error: */
_thread_seterrno(_thread_run, EINVAL);
if (cond == NULL || *cond == NULL) {
errno = EINVAL;
rval = -1;
break;
}
} else {
/* Process according to condition variable type: */
switch ((*cond)->c_type) {
/* Fast condition variable: */
case COND_TYPE_FAST:
/* Nothing to do here. */
break;
/* Check for errors: */
if (rval == 0) {
/* Destroy the contents of the condition structure: */
_thread_queue_init(&cond->c_queue);
cond->c_flags = 0;
/* Trap invalid condition variable types: */
default:
/* Return an invalid argument error: */
errno = EINVAL;
rval = -1;
break;
}
/* Check for errors: */
if (rval == 0) {
/* Destroy the contents of the condition structure: */
_thread_queue_init(&(*cond)->c_queue);
(*cond)->c_flags = 0;
free(*cond);
*cond = NULL;
}
}
/* Return the completion status: */
return (rval);
@ -116,39 +138,44 @@ pthread_cond_wait(pthread_cond_t * cond, pthread_mutex_t * mutex)
int rval = 0;
int status;
/* Block signals: */
_thread_kern_sig_block(&status);
/* Process according to condition variable type: */
switch (cond->c_type) {
/* Fast condition variable: */
case COND_TYPE_FAST:
/* Queue the running thread for the condition variable: */
_thread_queue_enq(&cond->c_queue, _thread_run);
/* Unlock the mutex: */
pthread_mutex_unlock(mutex);
/* Schedule the next thread: */
_thread_kern_sched_state(PS_COND_WAIT, __FILE__, __LINE__);
/* Block signals: */
_thread_kern_sig_block(NULL);
/* Lock the mutex: */
rval = pthread_mutex_lock(mutex);
break;
/* Trap invalid condition variable types: */
default:
/* Return an invalid argument error: */
_thread_seterrno(_thread_run, EINVAL);
if (cond == NULL || *cond == NULL) {
errno = EINVAL;
rval = -1;
break;
}
} else {
/* Block signals: */
_thread_kern_sig_block(&status);
/* Unblock signals: */
_thread_kern_sig_unblock(status);
/* Process according to condition variable type: */
switch ((*cond)->c_type) {
/* Fast condition variable: */
case COND_TYPE_FAST:
/* Queue the running thread for the condition variable: */
_thread_queue_enq(&(*cond)->c_queue, _thread_run);
/* Unlock the mutex: */
pthread_mutex_unlock(mutex);
/* Schedule the next thread: */
_thread_kern_sched_state(PS_COND_WAIT, __FILE__, __LINE__);
/* Block signals: */
_thread_kern_sig_block(NULL);
/* Lock the mutex: */
rval = pthread_mutex_lock(mutex);
break;
/* Trap invalid condition variable types: */
default:
/* Return an invalid argument error: */
errno = EINVAL;
rval = -1;
break;
}
/* Unblock signals: */
_thread_kern_sig_unblock(status);
}
/* Return the completion status: */
return (rval);
@ -161,59 +188,69 @@ pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex,
int rval = 0;
int status;
/* Block signals: */
_thread_kern_sig_block(&status);
/* Process according to condition variable type: */
switch (cond->c_type) {
/* Fast condition variable: */
case COND_TYPE_FAST:
/* Set the wakeup time: */
_thread_run->wakeup_time.ts_sec = abstime->ts_sec;
_thread_run->wakeup_time.ts_nsec = abstime->ts_nsec;
/* Reset the timeout flag: */
_thread_run->timeout = 0;
/* Queue the running thread for the condition variable: */
_thread_queue_enq(&cond->c_queue, _thread_run);
/* Unlock the mutex: */
if ((rval = pthread_mutex_unlock(mutex)) != 0) {
/*
* Cannot unlock the mutex, so remove the running
* thread from the condition variable queue:
*/
_thread_queue_deq(&cond->c_queue);
} else {
/* Schedule the next thread: */
_thread_kern_sched_state(PS_COND_WAIT, __FILE__, __LINE__);
/* Block signals: */
_thread_kern_sig_block(NULL);
/* Lock the mutex: */
if ((rval = pthread_mutex_lock(mutex)) != 0) {
}
/* Check if the wait timed out: */
else if (_thread_run->timeout) {
/* Return a timeout error: */
_thread_seterrno(_thread_run, EAGAIN);
rval = -1;
}
}
break;
/* Trap invalid condition variable types: */
default:
/* Return an invalid argument error: */
_thread_seterrno(_thread_run, EINVAL);
if (cond == NULL || *cond == NULL) {
errno = EINVAL;
rval = -1;
break;
}
} else {
/* Block signals: */
_thread_kern_sig_block(&status);
/* Unblock signals: */
_thread_kern_sig_unblock(status);
/* Process according to condition variable type: */
switch ((*cond)->c_type) {
/* Fast condition variable: */
case COND_TYPE_FAST:
/* Set the wakeup time: */
#if defined(__FreeBSD__)
_thread_run->wakeup_time.ts_sec = abstime->ts_sec;
_thread_run->wakeup_time.ts_nsec = abstime->ts_nsec;
#else
_thread_run->wakeup_time.tv_sec = abstime->tv_sec;
_thread_run->wakeup_time.tv_nsec = abstime->tv_nsec;
#endif
/* Reset the timeout flag: */
_thread_run->timeout = 0;
/* Queue the running thread for the condition variable: */
_thread_queue_enq(&(*cond)->c_queue, _thread_run);
/* Unlock the mutex: */
if ((rval = pthread_mutex_unlock(mutex)) != 0) {
/*
* Cannot unlock the mutex, so remove the running
* thread from the condition variable queue:
*/
_thread_queue_deq(&(*cond)->c_queue);
} else {
/* Schedule the next thread: */
_thread_kern_sched_state(PS_COND_WAIT, __FILE__, __LINE__);
/* Block signals: */
_thread_kern_sig_block(NULL);
/* Lock the mutex: */
if ((rval = pthread_mutex_lock(mutex)) != 0) {
}
/* Check if the wait timed out: */
else if (_thread_run->timeout) {
/* Return a timeout error: */
errno = EAGAIN;
rval = -1;
}
}
break;
/* Trap invalid condition variable types: */
default:
/* Return an invalid argument error: */
errno = EINVAL;
rval = -1;
break;
}
/* Unblock signals: */
_thread_kern_sig_unblock(status);
}
/* Return the completion status: */
return (rval);
@ -226,30 +263,35 @@ pthread_cond_signal(pthread_cond_t * cond)
int status;
pthread_t pthread;
/* Block signals: */
_thread_kern_sig_block(&status);
/* Process according to condition variable type: */
switch (cond->c_type) {
/* Fast condition variable: */
case COND_TYPE_FAST:
/* Bring the next thread off the condition queue: */
if ((pthread = _thread_queue_deq(&cond->c_queue)) != NULL) {
/* Allow the thread to run: */
pthread->state = PS_RUNNING;
}
break;
/* Trap invalid condition variable types: */
default:
/* Return an invalid argument error: */
_thread_seterrno(_thread_run, EINVAL);
if (cond == NULL || *cond == NULL) {
errno = EINVAL;
rval = -1;
break;
}
} else {
/* Block signals: */
_thread_kern_sig_block(&status);
/* Unblock signals: */
_thread_kern_sig_unblock(status);
/* Process according to condition variable type: */
switch ((*cond)->c_type) {
/* Fast condition variable: */
case COND_TYPE_FAST:
/* Bring the next thread off the condition queue: */
if ((pthread = _thread_queue_deq(&(*cond)->c_queue)) != NULL) {
/* Allow the thread to run: */
pthread->state = PS_RUNNING;
}
break;
/* Trap invalid condition variable types: */
default:
/* Return an invalid argument error: */
errno = EINVAL;
rval = -1;
break;
}
/* Unblock signals: */
_thread_kern_sig_unblock(status);
}
/* Return the completion status: */
return (rval);
@ -266,11 +308,11 @@ pthread_cond_broadcast(pthread_cond_t * cond)
_thread_kern_sig_block(&status);
/* Process according to condition variable type: */
switch (cond->c_type) {
switch ((*cond)->c_type) {
/* Fast condition variable: */
case COND_TYPE_FAST:
/* Enter a loop to bring all threads off the condition queue: */
while ((pthread = _thread_queue_deq(&cond->c_queue)) != NULL) {
while ((pthread = _thread_queue_deq(&(*cond)->c_queue)) != NULL) {
/* Allow the thread to run: */
pthread->state = PS_RUNNING;
}
@ -279,7 +321,7 @@ pthread_cond_broadcast(pthread_cond_t * cond)
/* Trap invalid condition variable types: */
default:
/* Return an invalid argument error: */
_thread_seterrno(_thread_run, EINVAL);
errno = EINVAL;
rval = -1;
break;
}

View File

@ -49,6 +49,7 @@ _thread_create(pthread_t * thread, const pthread_attr_t * attr,
int ret = 0;
int status;
pthread_t new_thread;
pthread_attr_t pattr;
void *stack;
/* Block signals: */
@ -60,15 +61,17 @@ _thread_create(pthread_t * thread, const pthread_attr_t * attr,
ret = EAGAIN;
} else {
/* Check if default thread attributes are required: */
if (attr == NULL) {
if (attr == NULL || *attr == NULL) {
/* Use the default thread attributes: */
attr = &pthread_attr_default;
pattr = &pthread_attr_default;
} else {
pattr = *attr;
}
/* Check if a stack was specified in the thread attributes: */
if ((stack = attr->stackaddr_attr) != NULL) {
if ((stack = pattr->stackaddr_attr) != NULL) {
}
/* Allocate memory for the stack: */
else if ((stack = (void *) malloc(attr->stacksize_attr)) == NULL) {
else if ((stack = (void *) malloc(pattr->stacksize_attr)) == NULL) {
/* Insufficient memory to create a thread: */
ret = EAGAIN;
free(new_thread);
@ -83,7 +86,7 @@ _thread_create(pthread_t * thread, const pthread_attr_t * attr,
new_thread->stack = stack;
new_thread->start_routine = start_routine;
new_thread->arg = arg;
if (attr->suspend == PTHREAD_CREATE_SUSPENDED) {
if (pattr->suspend == PTHREAD_CREATE_SUSPENDED) {
new_thread->state = PS_SUSPENDED;
} else {
new_thread->state = PS_RUNNING;
@ -148,19 +151,19 @@ _thread_create(pthread_t * thread, const pthread_attr_t * attr,
/* The stack starts high and builds down: */
#if defined(__FreeBSD__)
new_thread->saved_jmp_buf[0]._jb[2] = (int) (new_thread->stack + attr->stacksize_attr - sizeof(double));
new_thread->saved_jmp_buf[0]._jb[2] = (int) (new_thread->stack + pattr->stacksize_attr - sizeof(double));
#elif defined(__NetBSD__)
#if defined(__alpha)
new_thread->saved_jmp_buf[4 + R_SP] = (long) new_thread->stack + attr->stacksize_attr - sizeof(double);
new_thread->saved_jmp_buf[4 + R_SP] = (long) new_thread->stack + pattr->stacksize_attr - sizeof(double);
#else
new_thread->saved_jmp_buf[2] = (long) new_thread->stack + attr->stacksize_attr - sizeof(double);
new_thread->saved_jmp_buf[2] = (long) new_thread->stack + pattr->stacksize_attr - sizeof(double);
#endif
#else
#error "Don't recognize this operating system!"
#endif
/* Copy the thread attributes: */
memcpy(&new_thread->attr, attr, sizeof(pthread_attr_t));
memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr));
/*
* Check if this thread is to inherit the scheduling

View File

@ -31,11 +31,49 @@
*
*/
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
#include "pthread_private.h"
void _exit(int status)
{
int flags;
int i;
struct itimerval itimer;
/* Disable the interval timer: */
itimer.it_interval.tv_sec = 0;
itimer.it_interval.tv_usec = 0;
itimer.it_value.tv_sec = 0;
itimer.it_value.tv_usec = 0;
setitimer(ITIMER_VIRTUAL, &itimer, NULL);
/* Close the pthread kernel pipe: */
_thread_sys_close(_thread_kern_pipe[0]);
_thread_sys_close(_thread_kern_pipe[1]);
/*
* Enter a loop to set all file descriptors to blocking
* if they were not created as non-blocking:
*/
for (i = 0; i < _thread_dtablesize; i++) {
/* Check if this file descriptor is in use: */
if (_thread_fd_table[i] != NULL &&
!(_thread_fd_table[i]->flags & O_NONBLOCK)) {
/* Get the current flags: */
flags = _thread_sys_fcntl(i, F_GETFL, NULL);
/* Clear the nonblocking file descriptor flag: */
_thread_sys_fcntl(i, F_SETFL, flags & ~O_NONBLOCK);
}
}
/* Call the _exit syscall: */
_thread_sys__exit(status);
}
void
_thread_exit(char *fname, int lineno, char *string)
{

View File

@ -31,6 +31,7 @@
*
*/
#include <stdarg.h>
#include <unistd.h>
#include <fcntl.h>
#ifdef _THREAD_SAFE
#include <pthread.h>

View File

@ -31,6 +31,8 @@
*
*/
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#ifdef _THREAD_SAFE
#include <pthread.h>

View File

@ -202,18 +202,6 @@ _thread_main(int argc, char *argv[], char *env)
_thread_init();
return (main(argc, argv, env));
}
#else
/*
* Force our auto-initialization module to be pulled in from the library,
* by referencing a symbol that is defined in it.
*
* The auto-initialization module is a small C++ module. It has a static
* constructor that calls _thread_init() automatically, at the beginning
* of program execution. That eliminates the need for any special hooks
* in crt0.o.
*/
extern int _thread_autoinit_dummy_decl;
static int *_thread_autoinit_dummy_ref = &_thread_autoinit_dummy_decl;
#endif
#else
/*

View File

@ -250,18 +250,30 @@ __asm__("fnsave %0": :"m"(*fdata));
pthread->state == PS_FDW_WAIT ||
pthread->state == PS_SELECT_WAIT) {
/* Check if this thread is to wait forever: */
#if defined(__FreeBSD__)
if (pthread->wakeup_time.ts_sec == -1) {
#else
if (pthread->wakeup_time.tv_sec == -1) {
#endif
}
/*
* Check if this thread is to wakeup
* immediately or if it is past its wakeup
* time:
*/
#if defined(__FreeBSD__)
else if ((pthread->wakeup_time.ts_sec == 0 &&
pthread->wakeup_time.ts_nsec == 0) ||
(ts.ts_sec > pthread->wakeup_time.ts_sec) ||
((ts.ts_sec == pthread->wakeup_time.ts_sec) &&
(ts.ts_nsec >= pthread->wakeup_time.ts_nsec))) {
#else
else if ((pthread->wakeup_time.tv_sec == 0 &&
pthread->wakeup_time.tv_nsec == 0) ||
(ts.tv_sec > pthread->wakeup_time.tv_sec) ||
((ts.tv_sec == pthread->wakeup_time.tv_sec) &&
(ts.tv_nsec >= pthread->wakeup_time.tv_nsec))) {
#endif
/*
* Check if this thread is waiting on
* select:
@ -364,9 +376,48 @@ __asm__("fnsave %0": :"m"(*fdata));
}
/*
* Enter a loop to look for the first thread of the highest
* priority:
* priority that is ready to run:
*/
for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) {
/* Check if in single-threaded mode: */
if (_thread_single != NULL) {
/*
* Check if the current thread is
* the thread for which single-threaded
* mode is enabled:
*/
if (pthread == _thread_single) {
/*
* This thread is allowed
* to run.
*/
} else {
/*
* Walk up the signal handler
* parent thread tree to see
* if the current thread is
* descended from the thread
* for which single-threaded
* mode is enabled.
*/
pthread_nxt = pthread;
while(pthread_nxt != NULL &&
pthread_nxt != _thread_single) {
pthread_nxt = pthread->parent_thread;
}
/*
* Check if the current
* thread is not descended
* from the thread for which
* single-threaded mode is
* enabled.
*/
if (pthread_nxt == NULL)
/* Ignore this thread. */
continue;
}
}
/* Check if the current thread is unable to run: */
if (pthread->state != PS_RUNNING) {
}
@ -392,6 +443,45 @@ __asm__("fnsave %0": :"m"(*fdata));
* least recently.
*/
for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) {
/* Check if in single-threaded mode: */
if (_thread_single != NULL) {
/*
* Check if the current thread is
* the thread for which single-threaded
* mode is enabled:
*/
if (pthread == _thread_single) {
/*
* This thread is allowed
* to run.
*/
} else {
/*
* Walk up the signal handler
* parent thread tree to see
* if the current thread is
* descended from the thread
* for which single-threaded
* mode is enabled.
*/
pthread_nxt = pthread;
while(pthread_nxt != NULL &&
pthread_nxt != _thread_single) {
pthread_nxt = pthread->parent_thread;
}
/*
* Check if the current
* thread is not descended
* from the thread for which
* single-threaded mode is
* enabled.
*/
if (pthread_nxt == NULL)
/* Ignore this thread. */
continue;
}
}
/* Check if the current thread is unable to run: */
if (pthread->state != PS_RUNNING) {
/* Ignore threads that are not ready to run. */
@ -446,6 +536,45 @@ __asm__("fnsave %0": :"m"(*fdata));
* priority. 3. Became inactive least recently.
*/
for (pthread = _thread_link_list; pthread != NULL; pthread = pthread->nxt) {
/* Check if in single-threaded mode: */
if (_thread_single != NULL) {
/*
* Check if the current thread is
* the thread for which single-threaded
* mode is enabled:
*/
if (pthread == _thread_single) {
/*
* This thread is allowed
* to run.
*/
} else {
/*
* Walk up the signal handler
* parent thread tree to see
* if the current thread is
* descended from the thread
* for which single-threaded
* mode is enabled.
*/
pthread_nxt = pthread;
while(pthread_nxt != NULL &&
pthread_nxt != _thread_single) {
pthread_nxt = pthread->parent_thread;
}
/*
* Check if the current
* thread is not descended
* from the thread for which
* single-threaded mode is
* enabled.
*/
if (pthread_nxt == NULL)
/* Ignore this thread. */
continue;
}
}
/*
* Check if the current thread is unable to
* run:
@ -565,22 +694,37 @@ __asm__("fnsave %0": :"m"(*fdata));
* Check if this thread is to
* wait forever:
*/
#if defined(__FreeBSD__)
if (pthread->wakeup_time.ts_sec == -1) {
#else
if (pthread->wakeup_time.tv_sec == -1) {
#endif
}
/*
* Check if this thread is to
* wakeup immediately:
*/
#if defined(__FreeBSD__)
else if (pthread->wakeup_time.ts_sec == 0 &&
pthread->wakeup_time.ts_nsec == 0) {
#else
else if (pthread->wakeup_time.tv_sec == 0 &&
pthread->wakeup_time.tv_nsec == 0) {
#endif
}
/*
* Check if the current time
* is after the wakeup time:
*/
#if defined(__FreeBSD__)
else if ((ts.ts_sec > pthread->wakeup_time.ts_sec) ||
((ts.ts_sec == pthread->wakeup_time.ts_sec) &&
(ts.ts_nsec > pthread->wakeup_time.ts_nsec))) {
#else
else if ((ts.tv_sec > pthread->wakeup_time.tv_sec) ||
((ts.tv_sec == pthread->wakeup_time.tv_sec) &&
(ts.tv_nsec > pthread->wakeup_time.tv_nsec))) {
#endif
} else {
/*
* Calculate the time
@ -589,16 +733,26 @@ __asm__("fnsave %0": :"m"(*fdata));
* for the clock
* resolution:
*/
#if defined(__FreeBSD__)
ts1.ts_sec = pthread->wakeup_time.ts_sec - ts.ts_sec;
ts1.ts_nsec = pthread->wakeup_time.ts_nsec - ts.ts_nsec +
CLOCK_RES_NSEC;
#else
ts1.tv_sec = pthread->wakeup_time.tv_sec - ts.tv_sec;
ts1.tv_nsec = pthread->wakeup_time.tv_nsec - ts.tv_nsec +
CLOCK_RES_NSEC;
#endif
/*
* Check for
* underflow of the
* nanosecond field:
*/
#if defined(__FreeBSD__)
if (ts1.ts_nsec < 0) {
#else
if (ts1.tv_nsec < 0) {
#endif
/*
* Allow for
* the
@ -607,15 +761,24 @@ __asm__("fnsave %0": :"m"(*fdata));
* nanosecond
* field:
*/
#if defined(__FreeBSD__)
ts1.ts_sec--;
ts1.ts_nsec += 1000000000;
#else
ts1.tv_sec--;
ts1.tv_nsec += 1000000000;
#endif
}
/*
* Check for overflow
* of the nanosecond
* field:
*/
#if defined(__FreeBSD__)
if (ts1.ts_nsec >= 1000000000) {
#else
if (ts1.tv_nsec >= 1000000000) {
#endif
/*
* Allow for
* the
@ -624,8 +787,13 @@ __asm__("fnsave %0": :"m"(*fdata));
* nanosecond
* field:
*/
#if defined(__FreeBSD__)
ts1.ts_sec++;
ts1.ts_nsec -= 1000000000;
#else
ts1.tv_sec++;
ts1.tv_nsec -= 1000000000;
#endif
}
/*
* Convert the
@ -1100,11 +1268,20 @@ _thread_kern_select(int wait_reqd)
*/
if (wait_reqd && settimeout) {
/* Check if this thread wants to wait forever: */
#if defined(__FreeBSD__)
if (pthread->wakeup_time.ts_sec == -1) {
#else
if (pthread->wakeup_time.tv_sec == -1) {
#endif
}
/* Check if this thread doesn't want to wait at all: */
#if defined(__FreeBSD__)
else if (pthread->wakeup_time.ts_sec == 0 &&
pthread->wakeup_time.ts_nsec == 0) {
#else
else if (pthread->wakeup_time.tv_sec == 0 &&
pthread->wakeup_time.tv_nsec == 0) {
#endif
/* Override the caller's request to wait: */
wait_reqd = 0;
} else {
@ -1112,33 +1289,57 @@ _thread_kern_select(int wait_reqd)
* Calculate the time until this thread is
* ready, allowing for the clock resolution:
*/
#if defined(__FreeBSD__)
ts1.ts_sec = pthread->wakeup_time.ts_sec - ts.ts_sec;
ts1.ts_nsec = pthread->wakeup_time.ts_nsec - ts.ts_nsec +
CLOCK_RES_NSEC;
#else
ts1.tv_sec = pthread->wakeup_time.tv_sec - ts.tv_sec;
ts1.tv_nsec = pthread->wakeup_time.tv_nsec - ts.tv_nsec +
CLOCK_RES_NSEC;
#endif
/*
* Check for underflow of the nanosecond
* field:
*/
#if defined(__FreeBSD__)
if (ts1.ts_nsec < 0) {
#else
if (ts1.tv_nsec < 0) {
#endif
/*
* Allow for the underflow of the
* nanosecond field:
*/
#if defined(__FreeBSD__)
ts1.ts_sec--;
ts1.ts_nsec += 1000000000;
#else
ts1.tv_sec--;
ts1.tv_nsec += 1000000000;
#endif
}
/*
* Check for overflow of the nanosecond
* field:
*/
#if defined(__FreeBSD__)
if (ts1.ts_nsec >= 1000000000) {
#else
if (ts1.tv_nsec >= 1000000000) {
#endif
/*
* Allow for the overflow of the
* nanosecond field:
*/
#if defined(__FreeBSD__)
ts1.ts_sec++;
ts1.ts_nsec -= 1000000000;
#else
ts1.tv_sec++;
ts1.tv_nsec -= 1000000000;
#endif
}
/*
* Convert the timespec structure to a
@ -1552,28 +1753,56 @@ _thread_kern_set_timeout(struct timespec * timeout)
* Set the wakeup time to something that can be recognised as
* different to an actual time of day:
*/
#if defined(__FreeBSD__)
_thread_run->wakeup_time.ts_sec = -1;
_thread_run->wakeup_time.ts_nsec = -1;
#else
_thread_run->wakeup_time.tv_sec = -1;
_thread_run->wakeup_time.tv_nsec = -1;
#endif
}
/* Check if no waiting is required: */
#if defined(__FreeBSD__)
else if (timeout->ts_sec == 0 && timeout->ts_nsec == 0) {
#else
else if (timeout->tv_sec == 0 && timeout->tv_nsec == 0) {
#endif
/* Set the wake up time to 'immediately': */
#if defined(__FreeBSD__)
_thread_run->wakeup_time.ts_sec = 0;
_thread_run->wakeup_time.ts_nsec = 0;
#else
_thread_run->wakeup_time.tv_sec = 0;
_thread_run->wakeup_time.tv_nsec = 0;
#endif
} else {
/* Get the current time: */
gettimeofday(&tv, NULL);
TIMEVAL_TO_TIMESPEC(&tv, &current_time);
/* Calculate the time for the current thread to wake up: */
#if defined(__FreeBSD__)
_thread_run->wakeup_time.ts_sec = current_time.ts_sec + timeout->ts_sec;
_thread_run->wakeup_time.ts_nsec = current_time.ts_nsec + timeout->ts_nsec;
#else
_thread_run->wakeup_time.tv_sec = current_time.tv_sec + timeout->tv_sec;
_thread_run->wakeup_time.tv_nsec = current_time.tv_nsec + timeout->tv_nsec;
#endif
/* Check if the nanosecond field needs to wrap: */
#if defined(__FreeBSD__)
if (_thread_run->wakeup_time.ts_nsec >= 1000000000) {
#else
if (_thread_run->wakeup_time.tv_nsec >= 1000000000) {
#endif
/* Wrap the nanosecond field: */
#if defined(__FreeBSD__)
_thread_run->wakeup_time.ts_sec += 1;
_thread_run->wakeup_time.ts_nsec -= 1000000000;
#else
_thread_run->wakeup_time.tv_sec += 1;
_thread_run->wakeup_time.tv_nsec -= 1000000000;
#endif
}
}
return;

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Birrell.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
*
*/
#include <string.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
#include "pthread_private.h"
int pthread_multi_np()
{
/* Return to multi-threaded scheduling mode: */
_thread_single = NULL;
return(0);
}
#endif

View File

@ -41,62 +41,75 @@ pthread_mutex_init(pthread_mutex_t * mutex,
const pthread_mutexattr_t * mutex_attr)
{
enum pthread_mutextype type;
pthread_mutex_t pmutex;
int ret = 0;
int status;
/* Check if the mutex attributes specify some mutex other than fast: */
if (mutex_attr != NULL && mutex_attr->m_type != MUTEX_TYPE_FAST) {
/* Check if the mutex type is out of range: */
if (mutex_attr->m_type >= MUTEX_TYPE_MAX) {
if (mutex == NULL) {
errno = EINVAL;
ret = -1;
} else {
/* Check if default mutex attributes: */
if (mutex_attr == NULL || *mutex_attr == NULL) {
/* Default to a fast mutex: */
type = MUTEX_TYPE_FAST;
} else if ((*mutex_attr)->m_type >= MUTEX_TYPE_MAX) {
/* Return an invalid argument error: */
_thread_seterrno(_thread_run, EINVAL);
errno = EINVAL;
ret = -1;
} else {
/* Use the requested mutex type: */
type = mutex_attr->m_type;
}
} else {
/* Default to a fast mutex: */
type = MUTEX_TYPE_FAST;
}
/* Check no errors so far: */
if (ret == 0) {
/* Reset the mutex flags: */
mutex->m_flags = 0;
/* Block signals: */
_thread_kern_sig_block(&status);
/* Process according to mutex type: */
switch (type) {
/* Fast mutex: */
case MUTEX_TYPE_FAST:
/* Nothing to do here. */
break;
/* Counting mutex: */
case MUTEX_TYPE_COUNTING_FAST:
/* Reset the mutex count: */
mutex->m_data.m_count = 0;
break;
/* Trap invalid mutex types: */
default:
/* Return an invalid argument error: */
_thread_seterrno(_thread_run, EINVAL);
ret = -1;
break;
type = (*mutex_attr)->m_type;
}
/* Initialise the rest of the mutex: */
_thread_queue_init(&mutex->m_queue);
mutex->m_flags |= MUTEX_FLAGS_INITED;
mutex->m_owner = NULL;
mutex->m_type = type;
/* Check no errors so far: */
if (ret == 0) {
if ((pmutex = (pthread_mutex_t) malloc(sizeof(struct pthread_mutex))) == NULL) {
errno = ENOMEM;
ret = -1;
} else {
/* Reset the mutex flags: */
pmutex->m_flags = 0;
/* Unblock signals: */
_thread_kern_sig_unblock(status);
/* Block signals: */
_thread_kern_sig_block(&status);
/* Process according to mutex type: */
switch (type) {
/* Fast mutex: */
case MUTEX_TYPE_FAST:
/* Nothing to do here. */
break;
/* Counting mutex: */
case MUTEX_TYPE_COUNTING_FAST:
/* Reset the mutex count: */
pmutex->m_data.m_count = 0;
break;
/* Trap invalid mutex types: */
default:
/* Return an invalid argument error: */
errno = EINVAL;
ret = -1;
break;
}
if (ret == 0) {
/* Initialise the rest of the mutex: */
_thread_queue_init(&pmutex->m_queue);
pmutex->m_flags |= MUTEX_FLAGS_INITED;
pmutex->m_owner = NULL;
pmutex->m_type = type;
*mutex = pmutex;
} else {
free(pmutex);
*mutex = NULL;
}
/* Unblock signals: */
_thread_kern_sig_unblock(status);
}
}
}
/* Return the completion status: */
return (ret);
@ -108,38 +121,43 @@ pthread_mutex_destroy(pthread_mutex_t * mutex)
int ret = 0;
int status;
/* Block signals: */
_thread_kern_sig_block(&status);
/* Process according to mutex type: */
switch (mutex->m_type) {
/* Fast mutex: */
case MUTEX_TYPE_FAST:
/* Nothing to do here. */
break;
/* Counting mutex: */
case MUTEX_TYPE_COUNTING_FAST:
/* Reset the mutex count: */
mutex->m_data.m_count = 0;
break;
/* Trap undefined mutex types: */
default:
/* Return an invalid argument error: */
_thread_seterrno(_thread_run, EINVAL);
if (mutex == NULL || *mutex == NULL) {
errno = EINVAL;
ret = -1;
break;
} else {
/* Block signals: */
_thread_kern_sig_block(&status);
/* Process according to mutex type: */
switch ((*mutex)->m_type) {
/* Fast mutex: */
case MUTEX_TYPE_FAST:
/* Nothing to do here. */
break;
/* Counting mutex: */
case MUTEX_TYPE_COUNTING_FAST:
/* Reset the mutex count: */
(*mutex)->m_data.m_count = 0;
break;
/* Trap undefined mutex types: */
default:
/* Return an invalid argument error: */
errno = EINVAL;
ret = -1;
break;
}
/* Clean up the mutex in case that others want to use it: */
_thread_queue_init(&(*mutex)->m_queue);
(*mutex)->m_owner = NULL;
(*mutex)->m_flags = 0;
/* Unblock signals: */
_thread_kern_sig_unblock(status);
}
/* Clean up the mutex in case that others want to use it: */
_thread_queue_init(&mutex->m_queue);
mutex->m_owner = NULL;
mutex->m_flags = 0;
/* Unblock signals: */
_thread_kern_sig_unblock(status);
/* Return the completion status: */
return (ret);
}
@ -150,56 +168,61 @@ pthread_mutex_trylock(pthread_mutex_t * mutex)
int ret = 0;
int status;
/* Block signals: */
_thread_kern_sig_block(&status);
if (mutex == NULL || *mutex == NULL) {
errno = EINVAL;
ret = -1;
} else {
/* Block signals: */
_thread_kern_sig_block(&status);
/* Process according to mutex type: */
switch (mutex->m_type) {
/* Process according to mutex type: */
switch ((*mutex)->m_type) {
/* Fast mutex: */
case MUTEX_TYPE_FAST:
/* Check if this mutex is not locked: */
if (mutex->m_owner == NULL) {
/* Lock the mutex for the running thread: */
mutex->m_owner = _thread_run;
} else {
/* Return a busy error: */
_thread_seterrno(_thread_run, EBUSY);
ret = -1;
}
break;
/* Counting mutex: */
case MUTEX_TYPE_COUNTING_FAST:
/* Check if this mutex is locked: */
if (mutex->m_owner != NULL) {
/*
* Check if the mutex is locked by the running
* thread:
*/
if (mutex->m_owner == _thread_run) {
/* Increment the lock count: */
mutex->m_data.m_count++;
case MUTEX_TYPE_FAST:
/* Check if this mutex is not locked: */
if ((*mutex)->m_owner == NULL) {
/* Lock the mutex for the running thread: */
(*mutex)->m_owner = _thread_run;
} else {
/* Return a busy error: */
_thread_seterrno(_thread_run, EBUSY);
errno = EBUSY;
ret = -1;
}
} else {
/* Lock the mutex for the running thread: */
mutex->m_owner = _thread_run;
}
break;
break;
/* Counting mutex: */
case MUTEX_TYPE_COUNTING_FAST:
/* Check if this mutex is locked: */
if ((*mutex)->m_owner != NULL) {
/*
* Check if the mutex is locked by the running
* thread:
*/
if ((*mutex)->m_owner == _thread_run) {
/* Increment the lock count: */
(*mutex)->m_data.m_count++;
} else {
/* Return a busy error: */
errno = EBUSY;
ret = -1;
}
} else {
/* Lock the mutex for the running thread: */
(*mutex)->m_owner = _thread_run;
}
break;
/* Trap invalid mutex types: */
default:
/* Return an invalid argument error: */
_thread_seterrno(_thread_run, EINVAL);
ret = -1;
break;
}
default:
/* Return an invalid argument error: */
errno = EINVAL;
ret = -1;
break;
}
/* Unblock signals: */
_thread_kern_sig_unblock(status);
/* Unblock signals: */
_thread_kern_sig_unblock(status);
}
/* Return the completion status: */
return (ret);
@ -211,81 +234,86 @@ pthread_mutex_lock(pthread_mutex_t * mutex)
int ret = 0;
int status;
/* Block signals: */
_thread_kern_sig_block(&status);
if (mutex == NULL || *mutex == NULL) {
errno = EINVAL;
ret = -1;
} else {
/* Block signals: */
_thread_kern_sig_block(&status);
/* Process according to mutex type: */
switch (mutex->m_type) {
/* Process according to mutex type: */
switch ((*mutex)->m_type) {
/* Fast mutexes do not check for any error conditions: */
case MUTEX_TYPE_FAST:
/*
* Enter a loop to wait for the mutex to be locked by the
* current thread:
*/
while (mutex->m_owner != _thread_run) {
/* Check if the mutex is not locked: */
if (mutex->m_owner == NULL) {
/* Lock the mutex for this thread: */
mutex->m_owner = _thread_run;
} else {
/*
* Join the queue of threads waiting to lock
* the mutex:
*/
_thread_queue_enq(&mutex->m_queue, _thread_run);
case MUTEX_TYPE_FAST:
/*
* Enter a loop to wait for the mutex to be locked by the
* current thread:
*/
while ((*mutex)->m_owner != _thread_run) {
/* Check if the mutex is not locked: */
if ((*mutex)->m_owner == NULL) {
/* Lock the mutex for this thread: */
(*mutex)->m_owner = _thread_run;
} else {
/*
* Join the queue of threads waiting to lock
* the mutex:
*/
_thread_queue_enq(&(*mutex)->m_queue, _thread_run);
/* Block signals: */
_thread_kern_sched_state(PS_MUTEX_WAIT, __FILE__, __LINE__);
/* Block signals: */
_thread_kern_sched_state(PS_MUTEX_WAIT, __FILE__, __LINE__);
/* Block signals: */
_thread_kern_sig_block(NULL);
/* Block signals: */
_thread_kern_sig_block(NULL);
}
}
}
break;
break;
/* Counting mutex: */
case MUTEX_TYPE_COUNTING_FAST:
/*
* Enter a loop to wait for the mutex to be locked by the
* current thread:
*/
while (mutex->m_owner != _thread_run) {
/* Check if the mutex is not locked: */
if (mutex->m_owner == NULL) {
/* Lock the mutex for this thread: */
mutex->m_owner = _thread_run;
case MUTEX_TYPE_COUNTING_FAST:
/*
* Enter a loop to wait for the mutex to be locked by the
* current thread:
*/
while ((*mutex)->m_owner != _thread_run) {
/* Check if the mutex is not locked: */
if ((*mutex)->m_owner == NULL) {
/* Lock the mutex for this thread: */
(*mutex)->m_owner = _thread_run;
/* Reset the lock count for this mutex: */
mutex->m_data.m_count = 0;
} else {
/*
* Join the queue of threads waiting to lock
* the mutex:
*/
_thread_queue_enq(&mutex->m_queue, _thread_run);
/* Reset the lock count for this mutex: */
(*mutex)->m_data.m_count = 0;
} else {
/*
* Join the queue of threads waiting to lock
* the mutex:
*/
_thread_queue_enq(&(*mutex)->m_queue, _thread_run);
/* Block signals: */
_thread_kern_sched_state(PS_MUTEX_WAIT, __FILE__, __LINE__);
/* Block signals: */
_thread_kern_sched_state(PS_MUTEX_WAIT, __FILE__, __LINE__);
/* Block signals: */
_thread_kern_sig_block(NULL);
/* Block signals: */
_thread_kern_sig_block(NULL);
}
}
}
/* Increment the lock count for this mutex: */
mutex->m_data.m_count++;
break;
/* Increment the lock count for this mutex: */
(*mutex)->m_data.m_count++;
break;
/* Trap invalid mutex types: */
default:
/* Return an invalid argument error: */
_thread_seterrno(_thread_run, EINVAL);
ret = -1;
break;
}
default:
/* Return an invalid argument error: */
errno = EINVAL;
ret = -1;
break;
}
/* Unblock signals: */
_thread_kern_sig_unblock(status);
/* Unblock signals: */
_thread_kern_sig_unblock(status);
}
/* Return the completion status: */
return (ret);
@ -297,62 +325,67 @@ pthread_mutex_unlock(pthread_mutex_t * mutex)
int ret = 0;
int status;
/* Block signals: */
_thread_kern_sig_block(&status);
if (mutex == NULL || *mutex == NULL) {
errno = EINVAL;
ret = -1;
} else {
/* Block signals: */
_thread_kern_sig_block(&status);
/* Process according to mutex type: */
switch (mutex->m_type) {
/* Process according to mutex type: */
switch ((*mutex)->m_type) {
/* Fast mutexes do not check for any error conditions: */
case MUTEX_TYPE_FAST:
/* Check if the running thread is not the owner of the mutex: */
if (mutex->m_owner != _thread_run) {
/* Return an invalid argument error: */
_thread_seterrno(_thread_run, EINVAL);
ret = -1;
}
/*
* Get the next thread from the queue of threads waiting on
* the mutex:
*/
else if ((mutex->m_owner = _thread_queue_deq(&mutex->m_queue)) != NULL) {
/* Allow the new owner of the mutex to run: */
mutex->m_owner->state = PS_RUNNING;
}
break;
case MUTEX_TYPE_FAST:
/* Check if the running thread is not the owner of the mutex: */
if ((*mutex)->m_owner != _thread_run) {
/* Return an invalid argument error: */
errno = EINVAL;
ret = -1;
}
/*
* Get the next thread from the queue of threads waiting on
* the mutex:
*/
else if (((*mutex)->m_owner = _thread_queue_deq(&(*mutex)->m_queue)) != NULL) {
/* Allow the new owner of the mutex to run: */
(*mutex)->m_owner->state = PS_RUNNING;
}
break;
/* Counting mutex: */
case MUTEX_TYPE_COUNTING_FAST:
/* Check if the running thread is not the owner of the mutex: */
if (mutex->m_owner != _thread_run) {
/* Return an invalid argument error: */
_thread_seterrno(_thread_run, EINVAL);
ret = -1;
}
/* Check if there are still counts: */
else if (mutex->m_data.m_count) {
/* Decrement the count: */
mutex->m_data.m_count--;
}
/*
* Get the next thread from the queue of threads waiting on
* the mutex:
*/
else if ((mutex->m_owner = _thread_queue_deq(&mutex->m_queue)) != NULL) {
/* Allow the new owner of the mutex to run: */
mutex->m_owner->state = PS_RUNNING;
}
break;
case MUTEX_TYPE_COUNTING_FAST:
/* Check if the running thread is not the owner of the mutex: */
if ((*mutex)->m_owner != _thread_run) {
/* Return an invalid argument error: */
errno = EINVAL;
ret = -1;
}
/* Check if there are still counts: */
else if ((*mutex)->m_data.m_count) {
/* Decrement the count: */
(*mutex)->m_data.m_count--;
}
/*
* Get the next thread from the queue of threads waiting on
* the mutex:
*/
else if (((*mutex)->m_owner = _thread_queue_deq(&(*mutex)->m_queue)) != NULL) {
/* Allow the new owner of the mutex to run: */
(*mutex)->m_owner->state = PS_RUNNING;
}
break;
/* Trap invalid mutex types: */
default:
/* Return an invalid argument error: */
_thread_seterrno(_thread_run, EINVAL);
ret = -1;
break;
}
default:
/* Return an invalid argument error: */
errno = EINVAL;
ret = -1;
break;
}
/* Unblock signals: */
_thread_kern_sig_unblock(status);
/* Unblock signals: */
_thread_kern_sig_unblock(status);
}
/* Return the completion status: */
return (ret);

View File

@ -31,6 +31,7 @@
*
*/
#include <stdio.h>
#include <errno.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
#include "pthread_private.h"
@ -38,50 +39,138 @@
int
nanosleep(struct timespec * time_to_sleep, struct timespec * time_remaining)
{
int ret = 0;
struct timespec current_time;
struct timespec current_time1;
struct timespec remaining_time;
struct timeval tv;
/* Get the current time: */
gettimeofday(&tv, NULL);
TIMEVAL_TO_TIMESPEC(&tv, &current_time);
/* Check if the time to sleep is legal: */
#if defined(__FreeBSD__)
if (time_to_sleep == NULL || time_to_sleep->ts_nsec < 0 || time_to_sleep->ts_nsec > 1000000000) {
#else
if (time_to_sleep == NULL || time_to_sleep->tv_nsec < 0 || time_to_sleep->tv_nsec > 1000000000) {
#endif
/* Return an EINVAL error : */
errno = EINVAL;
ret = -1;
} else {
/* Get the current time: */
gettimeofday(&tv, NULL);
TIMEVAL_TO_TIMESPEC(&tv, &current_time);
/* Calculate the time for the current thread to wake up: */
_thread_run->wakeup_time.ts_sec = current_time.ts_sec + time_to_sleep->ts_sec;
_thread_run->wakeup_time.ts_nsec = current_time.ts_nsec + time_to_sleep->ts_nsec;
/* Calculate the time for the current thread to wake up: */
#if defined(__FreeBSD__)
_thread_run->wakeup_time.ts_sec = current_time.ts_sec + time_to_sleep->ts_sec;
_thread_run->wakeup_time.ts_nsec = current_time.ts_nsec + time_to_sleep->ts_nsec;
#else
_thread_run->wakeup_time.tv_sec = current_time.tv_sec + time_to_sleep->tv_sec;
_thread_run->wakeup_time.tv_nsec = current_time.tv_nsec + time_to_sleep->tv_nsec;
#endif
/* Check if the nanosecond field has overflowed: */
if (_thread_run->wakeup_time.ts_nsec >= 1000000000) {
/* Wrap the nanosecond field: */
_thread_run->wakeup_time.ts_sec += 1;
_thread_run->wakeup_time.ts_nsec -= 1000000000;
}
/* Reschedule the current thread to sleep: */
_thread_kern_sched_state(PS_SLEEP_WAIT, __FILE__, __LINE__);
/* Check if the nanosecond field has overflowed: */
#if defined(__FreeBSD__)
if (_thread_run->wakeup_time.ts_nsec >= 1000000000) {
#else
if (_thread_run->wakeup_time.tv_nsec >= 1000000000) {
#endif
/* Wrap the nanosecond field: */
#if defined(__FreeBSD__)
_thread_run->wakeup_time.ts_sec += 1;
_thread_run->wakeup_time.ts_nsec -= 1000000000;
#else
_thread_run->wakeup_time.tv_sec += 1;
_thread_run->wakeup_time.tv_nsec -= 1000000000;
#endif
}
/* Reschedule the current thread to sleep: */
_thread_kern_sched_state(PS_SLEEP_WAIT, __FILE__, __LINE__);
/* Check if the time remaining is to be returned: */
if (time_remaining != NULL) {
/* Get the current time: */
gettimeofday(&tv, NULL);
TIMEVAL_TO_TIMESPEC(&tv, &current_time1);
/* Return the actual time slept: */
time_remaining->ts_sec = time_to_sleep->ts_sec + current_time1.ts_sec - current_time.ts_sec;
time_remaining->ts_nsec = time_to_sleep->ts_nsec + current_time1.ts_nsec - current_time.ts_nsec;
/* Calculate the remaining time to sleep: */
#if defined(__FreeBSD__)
remaining_time.ts_sec = time_to_sleep->ts_sec + current_time.ts_sec - current_time1.ts_sec;
remaining_time.ts_nsec = time_to_sleep->ts_nsec + current_time.ts_nsec - current_time1.ts_nsec;
#else
remaining_time.tv_sec = time_to_sleep->tv_sec + current_time.tv_sec - current_time1.tv_sec;
remaining_time.tv_nsec = time_to_sleep->tv_nsec + current_time.tv_nsec - current_time1.tv_nsec;
#endif
/* Check if the nanosecond field has underflowed: */
if (time_remaining->ts_nsec < 0) {
#if defined(__FreeBSD__)
if (remaining_time.ts_nsec < 0) {
#else
if (remaining_time.tv_nsec < 0) {
#endif
/* Handle the underflow: */
time_remaining->ts_sec -= 1;
time_remaining->ts_nsec += 1000000000;
#if defined(__FreeBSD__)
remaining_time.ts_sec -= 1;
remaining_time.ts_nsec += 1000000000;
#else
remaining_time.tv_sec -= 1;
remaining_time.tv_nsec += 1000000000;
#endif
}
/* Check if the nanosecond field has overflowed: */
#if defined(__FreeBSD__)
if (remaining_time.ts_nsec >= 1000000000) {
#else
if (remaining_time.tv_nsec >= 1000000000) {
#endif
/* Handle the overflow: */
#if defined(__FreeBSD__)
remaining_time.ts_sec += 1;
remaining_time.ts_nsec -= 1000000000;
#else
remaining_time.tv_sec += 1;
remaining_time.tv_nsec -= 1000000000;
#endif
}
/* Check if the sleep was longer than the required time: */
if (time_remaining->ts_sec < 0) {
/* Reset the time teft: */
time_remaining->ts_sec = 0;
time_remaining->ts_nsec = 0;
#if defined(__FreeBSD__)
if (remaining_time.ts_sec < 0) {
#else
if (remaining_time.tv_sec < 0) {
#endif
/* Reset the time left: */
#if defined(__FreeBSD__)
remaining_time.ts_sec = 0;
remaining_time.ts_nsec = 0;
#else
remaining_time.tv_sec = 0;
remaining_time.tv_nsec = 0;
#endif
}
/* Check if the time remaining is to be returned: */
if (time_remaining != NULL) {
/* Return the actual time slept: */
#if defined(__FreeBSD__)
time_remaining->ts_sec = remaining_time.ts_sec;
time_remaining->ts_nsec = remaining_time.ts_nsec;
#else
time_remaining->tv_sec = remaining_time.tv_sec;
time_remaining->tv_nsec = remaining_time.tv_nsec;
#endif
}
/* Check if the entire sleep was not completed: */
#if defined(__FreeBSD__)
if (remaining_time.ts_nsec != 0 || remaining_time.ts_sec != 0) {
#else
if (remaining_time.tv_nsec != 0 || remaining_time.tv_sec != 0) {
#endif
/* Return an EINTR error : */
errno = EINTR;
ret = -1;
}
}
return (0);
return (ret);
}
#endif

View File

@ -31,6 +31,7 @@
*
*/
#include <stdarg.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#ifdef _THREAD_SAFE
@ -55,8 +56,8 @@ open(const char *path, int flags,...)
mode = va_arg(ap, int);
va_end(ap);
}
/* Open the file, forcing it to use non-blocking I/O operations: */
if ((fd = _thread_sys_open(path, flags | O_NONBLOCK, mode)) < 0) {
/* Open the file: */
if ((fd = _thread_sys_open(path, flags, mode)) < 0) {
}
/* Initialise the file descriptor table entry: */
else if (_thread_fd_table_init(fd) != 0) {
@ -65,12 +66,6 @@ open(const char *path, int flags,...)
/* Reset the file descriptor: */
fd = -1;
} else {
/*
* Save the file open flags so that they can be checked
* later:
*/
_thread_fd_table[fd]->flags = flags;
}
/* Unblock signals: */

View File

@ -58,6 +58,129 @@
*/
#define PANIC(string) _thread_exit(__FILE__,__LINE__,string)
/*
* Queue definitions.
*/
struct pthread_queue {
struct pthread *q_next;
struct pthread *q_last;
void *q_data;
};
/*
* Static queue initialization values.
*/
#define PTHREAD_QUEUE_INITIALIZER { NULL, NULL, NULL }
/*
* Mutex definitions.
*/
enum pthread_mutextype {
MUTEX_TYPE_FAST = 1,
MUTEX_TYPE_COUNTING_FAST = 2, /* Recursive */
MUTEX_TYPE_MAX
};
union pthread_mutex_data {
void *m_ptr;
int m_count;
};
struct pthread_mutex {
enum pthread_mutextype m_type;
struct pthread_queue m_queue;
struct pthread *m_owner;
union pthread_mutex_data m_data;
long m_flags;
};
/*
* Flags for mutexes.
*/
#define MUTEX_FLAGS_PRIVATE 0x01
#define MUTEX_FLAGS_INITED 0x02
#define MUTEX_FLAGS_BUSY 0x04
/*
* Static mutex initialization values.
*/
#define PTHREAD_MUTEX_INITIALIZER \
{ MUTEX_TYPE_FAST, PTHREAD_QUEUE_INITIALIZER, \
NULL, { NULL }, MUTEX_FLAGS_INITED }
struct pthread_mutex_attr {
enum pthread_mutextype m_type;
long m_flags;
};
/*
* Condition variable definitions.
*/
enum pthread_cond_type {
COND_TYPE_FAST,
COND_TYPE_MAX
};
struct pthread_cond {
enum pthread_cond_type c_type;
struct pthread_queue c_queue;
void *c_data;
long c_flags;
};
struct pthread_cond_attr {
enum pthread_cond_type c_type;
long c_flags;
};
/*
* Flags for condition variables.
*/
#define COND_FLAGS_PRIVATE 0x01
#define COND_FLAGS_INITED 0x02
#define COND_FLAGS_BUSY 0x04
/*
* Static cond initialization values.
*/
#define PTHREAD_COND_INITIALIZER \
{ COND_TYPE_FAST, PTHREAD_QUEUE_INITIALIZER, NULL, COND_FLAGS_INITED }
/*
* Cleanup definitions.
*/
struct pthread_cleanup {
struct pthread_cleanup *next;
void (*routine) ();
void *routine_arg;
};
/*
* Scheduling definitions.
*/
enum schedparam_policy {
SCHED_RR,
SCHED_IO,
SCHED_FIFO,
SCHED_OTHER
};
struct pthread_attr {
enum schedparam_policy schedparam_policy;
int prio;
int suspend;
int flags;
void *arg_attr;
void (*cleanup_attr) ();
void *stackaddr_attr;
size_t stacksize_attr;
};
struct sched_param {
int prio;
void *no_data;
};
/*
* Thread creation state attributes.
*/
@ -67,14 +190,11 @@
/*
* Miscellaneous definitions.
*/
#define PTHREAD_STACK_MIN 1024
#define PTHREAD_STACK_DEFAULT 65536
#define PTHREAD_DATAKEYS_MAX 256
#define PTHREAD_DEFAULT_PRIORITY 64
#define PTHREAD_MAX_PRIORITY 126
#define PTHREAD_MIN_PRIORITY 0
#define _POSIX_THREAD_ATTR_STACKSIZE
#define _POSIX_THREAD_DESTRUTOR_ITERATIONS 4
/*
* Clock resolution in nanoseconds.
@ -190,10 +310,10 @@ struct pthread {
* Thread start routine, argument, stack pointer and thread
* attributes.
*/
void *(*start_routine)(void *);
void *arg;
void *stack;
pthread_attr_t attr;
void *(*start_routine)(void *);
void *arg;
void *stack;
struct pthread_attr attr;
/*
* Thread-specific signal handler interface:
@ -319,6 +439,17 @@ SCLASS struct pthread *_thread_run
;
#endif
/*
* Ptr to the thread running in single-threaded mode or NULL if
* running multi-threaded (default POSIX behaviour).
*/
SCLASS struct pthread *_thread_single
#ifdef GLOBAL_PTHREAD_PRIVATE
= NULL;
#else
;
#endif
/* Ptr to the first thread in the thread linked list: */
SCLASS struct pthread *_thread_link_list
#ifdef GLOBAL_PTHREAD_PRIVATE
@ -372,7 +503,7 @@ SCLASS struct pthread *_thread_initial
#endif
/* Default thread attributes: */
SCLASS pthread_attr_t pthread_attr_default
SCLASS struct pthread_attr pthread_attr_default
#ifdef GLOBAL_PTHREAD_PRIVATE
= { SCHED_RR, PTHREAD_DEFAULT_PRIORITY, PTHREAD_CREATE_RUNNING,
PTHREAD_CREATE_JOINABLE, NULL, NULL, NULL, PTHREAD_STACK_DEFAULT };
@ -570,6 +701,7 @@ pid_t _thread_sys_fork(void);
pid_t _thread_sys_tcgetpgrp(int);
ssize_t _thread_sys_read(int, void *, size_t);
ssize_t _thread_sys_write(int, const void *, size_t);
void _thread_sys__exit(int);
#endif
/* #include <fcntl.h> */

View File

@ -0,0 +1,70 @@
/*
* Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Birrell.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
*
*/
#include <errno.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
#include "pthread_private.h"
int
pthread_resume_np(pthread_t thread)
{
int ret = -1;
pthread_t pthread;
/*
* Search for the thread in the linked list.
*/
for (pthread = _thread_link_list; pthread != NULL && ret == -1; pthread = pthread->nxt) {
/* Is this the thread? */
if (pthread == thread) {
/* Found the thread. Is it suspended? */
if (pthread->state == PS_SUSPENDED) {
/* Allow the thread to run. */
pthread->state = PS_RUNNING;
ret = 0;
} else if (pthread->state == PS_RUNNING) {
/* Thread is already running. */
ret = 0;
} else {
/* Thread is in some other state. */
_thread_seterrno(_thread_run,EINVAL);
}
}
}
/* Check if thread was not found. */
if (ret == -1) {
/* No such thread */
_thread_seterrno(_thread_run,ESRCH);
}
return(ret);
}
#endif

View File

@ -142,36 +142,29 @@ select(int numfds, fd_set * readfds, fd_set * writefds,
if (ret > 0) {
if (readfds != NULL) {
FD_ZERO(readfds);
for (i = 0; i < numfds; i++) {
if (FD_ISSET(i, &data.readfds)) {
FD_SET(i, readfds);
if (FD_ISSET(i, readfds) &&
!FD_ISSET(i, &data.readfds)) {
FD_CLR(i, readfds);
}
}
}
if (writefds != NULL) {
FD_ZERO(writefds);
for (i = 0; i < numfds; i++) {
if (FD_ISSET(i, &data.writefds)) {
FD_SET(i, writefds);
if (FD_ISSET(i, writefds) &&
!FD_ISSET(i, &data.writefds)) {
FD_CLR(i, writefds);
}
}
}
if (exceptfds != NULL) {
FD_ZERO(exceptfds);
for (i = 0; i < numfds; i++) {
if (FD_ISSET(i, &data.exceptfds)) {
FD_SET(i, exceptfds);
if (FD_ISSET(i, exceptfds) &&
!FD_ISSET(i, &data.exceptfds)) {
FD_CLR(i, exceptfds);
}
}
}
} else {
if (exceptfds != NULL)
FD_ZERO(exceptfds);
if (writefds != NULL)
FD_ZERO(writefds);
if (readfds != NULL)
FD_ZERO(readfds);
}
return (ret);

View File

@ -31,6 +31,8 @@
*
*/
#include <signal.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
@ -40,6 +42,7 @@ void
_thread_sig_handler(int sig, int code, struct sigcontext * scp)
{
char c;
int i;
pthread_t pthread;
/*
@ -67,16 +70,52 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp)
} else {
/* Handle depending on signal type: */
switch (sig) {
/* Interval timer used for timeslicing: */
/* Interval timer used for timeslicing: */
case SIGVTALRM:
/*
* Don't add the signal to any thread. Just want to
* call
* call the scheduler:
*/
/* the scheduler: */
break;
/* Signals specific to the running thread: */
/* Child termination: */
case SIGCHLD:
/*
* Enter a loop to process each thread in the linked
* list:
*/
for (pthread = _thread_link_list; pthread != NULL;
pthread = pthread->nxt) {
/*
* Add the signal to the set of pending
* signals:
*/
pthread->sigpend[sig] += 1;
if (pthread->state == PS_WAIT_WAIT) {
/* Reset the error: */
/* There should be another flag so that this is not required! ### */
_thread_seterrno(pthread, 0);
/* Change the state of the thread to run: */
pthread->state = PS_RUNNING;
}
}
/*
* Go through the file list and set all files
* to non-blocking again in case the child
* set some of them to block. Sigh.
*/
for (i = 0; i < _thread_dtablesize; i++) {
/* Check if this file is used: */
if (_thread_fd_table[i] != NULL) {
/* Set the file descriptor to non-blocking: */
_thread_sys_fcntl(i, F_SETFL, _thread_fd_table[i]->flags | O_NONBLOCK);
}
}
break;
/* Signals specific to the running thread: */
case SIGBUS:
case SIGEMT:
case SIGFPE:
@ -88,7 +127,7 @@ _thread_sig_handler(int sig, int code, struct sigcontext * scp)
_thread_run->sigpend[sig] += 1;
break;
/* Signals to send to all threads: */
/* Signals to send to all threads: */
default:
/*
* Enter a loop to process each thread in the linked

View File

@ -47,6 +47,9 @@ sigsuspend(const sigset_t * set)
/* Save the current sigmal mask: */
oset = _thread_run->sigmask;
/* Combine the caller's mask with the current one: */
_thread_run->sigmask |= *set;
/* Wait for a signal: */
_thread_kern_sched_state(PS_SIGWAIT, __FILE__, __LINE__);

View File

@ -0,0 +1,44 @@
/*
* Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Birrell.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
*
*/
#include <string.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
#include "pthread_private.h"
int pthread_single_np()
{
/* Enter single-threaded (non-POSIX) scheduling mode: */
_thread_single = _thread_run;
return(0);
}
#endif

View File

@ -39,12 +39,12 @@
#include "pthread_private.h"
/* Static variables: */
static struct pthread_key key_table[PTHREAD_DATAKEYS_MAX];
static struct pthread_key key_table[PTHREAD_KEYS_MAX];
int
pthread_keycreate(pthread_key_t * key, void (*destructor) (void *))
pthread_key_create(pthread_key_t * key, void (*destructor) (void *))
{
for ((*key) = 0; (*key) < PTHREAD_DATAKEYS_MAX; (*key)++) {
for ((*key) = 0; (*key) < PTHREAD_KEYS_MAX; (*key)++) {
if (key_table[(*key)].count == 0) {
key_table[(*key)].count++;
key_table[(*key)].destructor = destructor;
@ -63,7 +63,7 @@ pthread_key_delete(pthread_key_t key)
/* Block signals: */
_thread_kern_sig_block(&status);
if (key < PTHREAD_DATAKEYS_MAX) {
if (key < PTHREAD_KEYS_MAX) {
switch (key_table[key].count) {
case 1:
key_table[key].destructor = NULL;
@ -94,8 +94,8 @@ _thread_cleanupspecific(void)
/* Block signals: */
_thread_kern_sig_block(&status);
for (itr = 0; itr < _POSIX_THREAD_DESTRUTOR_ITERATIONS; itr++) {
for (key = 0; key < PTHREAD_DATAKEYS_MAX; key++) {
for (itr = 0; itr < PTHREAD_DESTRUCTOR_ITERATIONS; itr++) {
for (key = 0; key < PTHREAD_KEYS_MAX; key++) {
if (_thread_run->specific_data_count) {
if (_thread_run->specific_data[key]) {
data = (void *) _thread_run->specific_data[key];
@ -125,8 +125,8 @@ static inline const void **
pthread_key_allocate_data(void)
{
const void **new_data;
if ((new_data = (const void **) malloc(sizeof(void *) * PTHREAD_DATAKEYS_MAX)) != NULL) {
memset((void *) new_data, 0, sizeof(void *) * PTHREAD_DATAKEYS_MAX);
if ((new_data = (const void **) malloc(sizeof(void *) * PTHREAD_KEYS_MAX)) != NULL) {
memset((void *) new_data, 0, sizeof(void *) * PTHREAD_KEYS_MAX);
}
return (new_data);
}
@ -154,7 +154,7 @@ pthread_setspecific(pthread_key_t key, const void *value)
}
if ((pthread->specific_data) || (pthread->specific_data = pthread_key_allocate_data())) {
if ((key < PTHREAD_DATAKEYS_MAX) && (key_table)) {
if ((key < PTHREAD_KEYS_MAX) && (key_table)) {
if (key_table[key].count) {
if (pthread->specific_data[key] == NULL) {
if (value != NULL) {
@ -213,7 +213,7 @@ pthread_getspecific(pthread_key_t key, void **p_data)
rval = -1;
}
/* Check if there is specific data: */
else if (pthread->specific_data != NULL && (key < PTHREAD_DATAKEYS_MAX) && (key_table)) {
else if (pthread->specific_data != NULL && (key < PTHREAD_KEYS_MAX) && (key_table)) {
/* Check if this key has been used before: */
if (key_table[key].count) {
/* Return the value: */

View File

@ -0,0 +1,67 @@
/*
* Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. 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.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by John Birrell.
* 4. Neither the name of the author nor the names of any co-contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
*
*/
#include <errno.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
#include "pthread_private.h"
int
pthread_suspend_np(pthread_t thread)
{
int ret = -1;
pthread_t pthread;
/*
* Search for the thread in the linked list.
*/
for (pthread = _thread_link_list; pthread != NULL && ret == -1; pthread = pthread->nxt) {
/* Is this the thread? */
if (pthread == thread) {
/* Found the thread. Is it running? */
if (pthread->state != PS_RUNNING &&
pthread->state != PS_SUSPENDED) {
/* The thread operation has been interrupted */
_thread_seterrno(pthread,EINTR);
}
/* Suspend the thread. */
pthread->state = PS_SUSPENDED;
ret = 0;
}
}
/* Check if thread was not found. */
if (ret == -1) {
/* No such thread */
_thread_seterrno(_thread_run,ESRCH);
}
return(ret);
}
#endif

View File

@ -20,6 +20,7 @@ PRECIOUSLIB= yes
.include "${.CURDIR}/gen/Makefile.inc"
.include "${.CURDIR}/gmon/Makefile.inc"
.include "${.CURDIR}/locale/Makefile.inc"
.include "${.CURDIR}/man/Makefile.inc"
.include "${.CURDIR}/net/Makefile.inc"
.include "${.CURDIR}/nls/Makefile.inc"
.include "${.CURDIR}/quad/Makefile.inc"
@ -38,24 +39,8 @@ CFLAGS+= -DYP
.endif
.include "${.CURDIR}/${MACHINE}/sys/Makefile.inc"
KQSRCS= adddi3.c anddi3.c ashldi3.c ashrdi3.c cmpdi2.c divdi3.c iordi3.c \
lshldi3.c lshrdi3.c moddi3.c muldi3.c negdi2.c notdi2.c qdivrem.c \
subdi3.c ucmpdi2.c udivdi3.c umoddi3.c xordi3.c
KSRCS= bcmp.c ffs.c index.c mcount.c rindex.c strcat.c strcmp.c strcpy.c \
strlen.c strncpy.c
libkern: libkern.gen libkern.${MACHINE}
libkern.gen: ${KQSRCS} ${KSRCS}
cp -p ${.CURDIR}/quad/quad.h ${.ALLSRC} /sys/libkern
libkern.${MACHINE}:: ${KMSRCS}
.if defined(KMSRCS) && !empty(KMSRCS)
cp -p ${.ALLSRC} /sys/libkern/${MACHINE}
.endif
#beforeinstall: tags
# ${INSTALL} ${COPY} -o bin -g bin -m 444 tags /var/db/libc.tags
beforeinstall: tags
${INSTALL} ${COPY} -o bin -g bin -m 444 tags /var/db/libc_r.tags
tags: ${SRCS}
ctags ${.ALLSRC:M*.c}

View File

@ -0,0 +1,17 @@
# $Id$
# POSIX thread man files
.PATH: ${.CURDIR}/man
MAN3+= pthread_create.3 \
pthread_detach.3 \
pthread_equal.3 \
pthread_exit.3 \
pthread_getspecific.3 \
pthread_join.3 \
pthread_key_create.3 \
pthread_key_delete.3 \
pthread_once.3 \
pthread_self.3 \
pthread_setspecific.3

View File

@ -0,0 +1,109 @@
.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. 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.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by John Birrell.
.\" 4. Neither the name of the author nor the names of any co-contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
.\"
.Dd April 4, 1996
.Dt PTHREAD_CREATE 3
.Os BSD 4
.Sh NAME
.Nm pthread_create
.Nd create a new thread
.Sh SYNOPSIS
.Fd #include <pthread.h>
.Ft int
.Fn pthread_create "pthread_t *thread" "const pthread_attr_t *attr" "void *(*start_routine)(void *)" "void *arg"
.Sh DESCRIPTION
The
.Fn pthread_create
function is used to create a new thread, with attributes specified by
.Fa attr ,
within a process. If
.Fa attr
is NULL, the default attributes are used. If the attributes specified by
.Fa attr
are modified later, the thread's attributes are not affected. Upon
successful completion
.Fn pthread_create
will store the ID of the created thread in the location specified by
.Fa thread .
.Pp
The thread is created executing
.Fa start_routine
with
.Fa arg
as its sole argument. If the
.Fa start_routine
returns, the effect is as if there was an implicit call to
.Fn pthread_exit
using the return value of
.Fa start_toutine
as the exit status. Note that the thread in which
.Fn main
was originally invoked differs from this. When it returns from
.Fn main ,
the effect is as if there was an implicit call to
.Fn exit using the return value of
.Fn main
as the exit status.
.Pp
The signal state of the new thread is initialized as:
.Bl -bullet -offset indent
.It
The signal mask is inherited from the creating thread.
.It
The set of signals pending for the new thread is empty.
.El
.Sh RETURN VALUES
If successful, the
.Fn pthread_create
function will return zero. Otherwise an error number will be returned to
indicate the error.
.Sh ERRORS
.Fn pthread_create
will fail if:
.Bl -tag -width Er
.It Bq Er EAGAIN
The system lacked the necessary resources to create another thread, or
the system-imposed limit on the total number of threads in a process
[PTHREAD_THREADS_MAX] would be exceeded.
.It Bq Er EINVAL
The value specified by
.Fa attr
is invalid.
.El
.Pp
.Sh SEE ALSO
.Xr pthread_exit 3 ,
.Xr pthread_join 3 ,
.Xr fork 2
.Sh STANDARDS
.Fn pthread_create
is expected to conform to IEEE
.Pq Dq Tn POSIX
Std 1003.1c when it is published.

View File

@ -0,0 +1,79 @@
.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. 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.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by John Birrell.
.\" 4. Neither the name of the author nor the names of any co-contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
.\"
.Dd April 4, 1996
.Dt PTHREAD_DETACH 3
.Os BSD 4
.Sh NAME
.Nm pthread_detach
.Nd detach a thread
.Sh SYNOPSIS
.Fd #include <pthread.h>
.Ft int
.Fn pthread_detach "pthread_t thread"
.Sh DESCRIPTION
The
.Fn pthread_detach
function is used to indicate to the implementation that storage for the
thread
.Fa thread
can be reclaimed when the thread terminates. If
.Fa thread
has not terminated,
.Fn pthread_detach
will not cause it to terminate. The effect of multiple
.Fn pthread_detach
calls on the same target thread is unspecified.
.Sh RETURN VALUES
If successful, the
.Fn pthread_detach
function will return zero. Otherwise an error number will be returned to
indicate the error.
.Sh ERRORS
.Fn pthread_detach
will fail if:
.Bl -tag -width Er
.It Bq Er EINVAL
The implementation has detected that the value specified by
.Fa thread
does not refer to a joinable thread.
.It Bq Er ESRCH
No thread could be found corresponding to that specified by the given
thread ID,
.Fa thread .
.El
.Pp
.Sh SEE ALSO
.Xr pthread_join 3
.Sh STANDARDS
.Fn pthread_detach
is expected to conform to IEEE
.Pq Dq Tn POSIX
Std 1003.1c when it is published.

View File

@ -0,0 +1,66 @@
.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. 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.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by John Birrell.
.\" 4. Neither the name of the author nor the names of any co-contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
.\"
.Dd April 4, 1996
.Dt PTHREAD_EQUAL 3
.Os BSD 4
.Sh NAME
.Nm pthread_equal
.Nd compare thread IDs
.Sh SYNOPSIS
.Fd #include <pthread.h>
.Ft int
.Fn pthread_equal "pthread_t t1" "pthread_t t2"
.Sh DESCRIPTION
The
.Fn pthread_equal
function compares the thread IDs
.Fa t1
and
.Fa t2 .
.Sh RETURN VALUES
The
.Fn pthread_equal
function will non-zero if the thread IDs
.Fa t1
and
.Fa t2
correspond to the same thread, otherwise it will return zero.
.Sh ERRORS
None.
.Pp
.Sh SEE ALSO
.Xr pthread_create 3 ,
.Xr pthread_exit 3
.Sh STANDARDS
.Fn pthread_equal
is expected to conform to IEEE
.Pq Dq Tn POSIX
Std 1003.1c when it is published.

View File

@ -0,0 +1,99 @@
.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. 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.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by John Birrell.
.\" 4. Neither the name of the author nor the names of any co-contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
.\"
.Dd April 4, 1996
.Dt PTHREAD_EXIT 3
.Os BSD 4
.Sh NAME
.Nm pthread_exit
.Nd terminate the calling thread
.Sh SYNOPSIS
.Fd #include <pthread.h>
.Ft void
.Fn pthread_exit "void *value_ptr"
.Sh DESCRIPTION
The
.Fn pthread_exit
function terminates the calling thread and makes the value
.Fa value_ptr
available to any successful join with the terminating thread. Any
cancellation cleanup handlers that have been pushed and are not yet popped
are popped in the reverse order that they were pushed and then executed.
After all cancellation handlers have been executed, if the thread has any
thread-specific data, appropriate destructor functions are called in an
unspecified order. Thread termination does not release any application
visible process resources, including, but not limited to, mutexes and
file descriptors, nor does it perform any process level cleanup
actions, including, but not limited to, calling
.Fn atexit
routines that may exist.
.Pp
An implicit call to
.Fn pthread_exit
is made when a thread other than the thread in which
.Fn main
was first invoked returns from the start routine that was used to create
it. The function's return value serves as the thread's exit status.
.Pp
The behavior of
.Fn pthread_exit
is undefied if called from a cancellation handler or destructor function
that was invoked as the result of an implicit or explicit call to
.Fn pthread_exit .
.Pp
After a thread has terminated, the result of access to local (auto)
variables of the thread is undefined. Thus, references to local variables
of the exiting thread should not be used for the
.Fn pthread_exit
.Fa value_ptr
parameter value.
.Pp
The process will exit with an exit status of 0 after the last thread has
been terminated. The behavior is as if the implementation called
.Fn exit
with a zero argument at thread termination time.
.Pp
.Sh RETURN VALUES
The
.Fn pthread_exit
function cannot return to its caller.
.Sh ERRORS
None.
.Pp
.Sh SEE ALSO
.Xr pthread_create 3 ,
.Xr pthread_join 3 ,
.Xr exit 2,
.Xr _exit 2
.Sh STANDARDS
.Fn pthread_exit
is expected to conform to IEEE
.Pq Dq Tn POSIX
Std 1003.1c when it is published.

View File

@ -0,0 +1,80 @@
.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. 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.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by John Birrell.
.\" 4. Neither the name of the author nor the names of any co-contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
.\"
.Dd April 4, 1996
.Dt PTHREAD_GETSPECIFIC 3
.Os BSD 4
.Sh NAME
.Nm pthread_getspecific
.Nd get a thread-specific data value
.Sh SYNOPSIS
.Fd #include <pthread.h>
.Ft void *
.Fn pthread_getspecific "pthread_key_t key"
.Sh DESCRIPTION
The
.Fn pthread_getspecific
function returns the value currently bound to the specified
.Fa key
on behalf of the calling thread.
.Pp
The effect of calling
.Fn pthread_getspecific
with a
.Fa key
value not obtained from
.Fn pthread_key_create
or after
.Fa key
has been deleted with
.Fn pthread_key_delete
is undefined.
.Pp
.Fn pthread_getspecific
may be called from a thread-specific data destructor function.
.Sh RETURN VALUES
The
.Fn pthread_getspecific
function will return the thread-specific data value associated with the given
.Fa key .
If no thread-specific data value is associated with
.Fa key ,
then the value NULL is returned.
.Sh ERRORS
None.
.Sh SEE ALSO
.Xr pthread_key_create 3 ,
.Xr pthread_key_delete 3
.Xr pthread_setspecific 3
.Sh STANDARDS
.Fn pthread_getspecific
is expected to conform to IEEE
.Pq Dq Tn POSIX
Std 1003.1c when it is published.

View File

@ -0,0 +1,100 @@
.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. 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.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by John Birrell.
.\" 4. Neither the name of the author nor the names of any co-contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
.\"
.Dd April 4, 1996
.Dt PTHREAD_JOIN 3
.Os BSD 4
.Sh NAME
.Nm pthread_join
.Nd wait for thread termination
.Sh SYNOPSIS
.Fd #include <pthread.h>
.Ft int
.Fn pthread_join "pthread_t thread" "void **value_ptr"
.Sh DESCRIPTION
The
.Fn pthread_join
function suspends execution of the calling thread until the target
.Fa thread
terminates unless the target
.Fa thread
has already terminated.
.Pp
On return from a successful
.Fn pthread_join
call with a non-NULL
.Fa value_ptr
argument, the value passed to
.Fn pthread_exit
by the terminating thread is stored in the location referenced by
.Fa value_ptr .
When a
.Fn pthread_join
returns successfully, the target thread has been terminated. The results
of multiple simultaneous calls to
.Fn pthread_join
specifying the same target thread are undefined. If the thread calling
.Fn pthread_join
is cancelled, then the target thread is not detached.
.Pp
A thread that has exited but remains unjoined counts against
[_POSIX_THREAD_THREADS_MAX].
.Pp
.Sh RETURN VALUES
If successful, the
.Fn pthread_join
function will return zero. Otherwise an error number will be returned to
indicate the error.
.Sh ERRORS
.Fn pthread_join
will fail if:
.Bl -tag -width Er
.It Bq Er EINVAL
The implementation has detected that the value specified by
.Fa thread
does not refer to a joinable thread.
.It Bq Er ESRCH
No thread could be found corresponding to that specified by the given
thread ID,
.Fa thread .
.It Bq Er EDEADLK
A deadlock was detected or the value of
.Fa thread
specifies the calling thread.
.El
.Pp
.Sh SEE ALSO
.Xr pthread_create 3 ,
.Xr wait 2
.Sh STANDARDS
.Fn pthread_join
is expected to conform to IEEE
.Pq Dq Tn POSIX
Std 1003.1c when it is published.

View File

@ -0,0 +1,98 @@
.\" Copyright (c) 1996 John Birrell <jb@cimlogic.com.au>.
.\" All rights reserved.
.\"
.\" Redistribution and use in source and binary forms, with or without
.\" modification, are permitted provided that the following conditions
.\" are met:
.\" 1. Redistributions of source code must retain the above copyright
.\" notice, this list of conditions and the following disclaimer.
.\" 2. 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.
.\" 3. All advertising materials mentioning features or use of this software
.\" must display the following acknowledgement:
.\" This product includes software developed by John Birrell.
.\" 4. Neither the name of the author nor the names of any co-contributors
.\" may be used to endorse or promote products derived from this software
.\" without specific prior written permission.
.\"
.\" THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL 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 REGENTS 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.
.\"
.Dd April 4, 1996
.Dt PTHREAD_KEY_CREATE 3
.Os BSD 4
.Sh NAME
.Nm pthread_key_create
.Nd thread-specific data key creation
.Sh SYNOPSIS
.Fd #include <pthread.h>
.Ft int
.Fn pthread_key_create "pthread_key_t *key" "void (*destructor)(void *)"
.Sh DESCRIPTION
The
.Fn pthread_key_create
function creates a thread-specific data key visible to all threads in the
process. Key values provided by
.Fn pthread_key_create
are opaque objects used to locate thread-specific data. Although the same
key value may be used by different threads, the values bound to the key
by
.Fn pthread_setspecific
are maintained on a per-thread basis and persist for the life of the calling
thread.
.Pp
Upon key creation, the value NULL is associated with the new key in all
active threads. Upon thread creation, the value NULL is associated with all
defined keys in the new thread.
.Pp
An optional destructor function may be associated with each key value. At
thread exit, if a key value has a non-NULL destructor pointer, and the
thread has a non-NULL value associated with the key, the function pointed
to is called with the current associated value as its sole argument. The
order of destructor calls is unspecified if more than one destructor exists
for a thread when it exits.
.Pp
If, after all the destructors have been called for all non-NULL values
with associated destructors, there are still some non-NULL values with
associated destructors, then the process is repeated. If, after at least
[PTHREAD_DESTRUCTOR_ITERATIONS] iterations of destructor calls for
outstanding non-NULL values, there are still some non-NULL values with
associated destructors, the implementation stops calling destructors.
.Sh RETURN VALUES
If successful, the
.Fn pthread_key_create
function will store the newly created key value at the location specified by
.Fa key
and returns zero. Otherwise an error number will be returned to indicate
the error.
.Sh ERRORS
.Fn pthread_key_create
will fail if:
.Bl -tag -width Er
.It Bq Er EAGAIN
The system lacked the necessary resources to create another thread-specific
data key, or the system-imposed limit on the total number of keys per process
[PTHREAD_KEYS_MAX] would be exceeded.
.It Bq Er ENOMEM
Insufficient memory exists to create the key.
.El
.Pp
.Sh SEE ALSO
.Xr pthread_getspecific 3 ,
.Xr pthread_setspecific 3 ,
.Xr pthread_key_delete 3
.Sh STANDARDS
.Fn pthread_key_create
is expected to conform to IEEE
.Pq Dq Tn POSIX
Std 1003.1c when it is published.

Some files were not shown because too many files have changed in this diff Show More