diff options
Diffstat (limited to 'lib/libc_r/uthread')
134 files changed, 18852 insertions, 0 deletions
diff --git a/lib/libc_r/uthread/Makefile.inc b/lib/libc_r/uthread/Makefile.inc new file mode 100644 index 0000000..1ec09c5 --- /dev/null +++ b/lib/libc_r/uthread/Makefile.inc @@ -0,0 +1,138 @@ +# $FreeBSD$ + +# uthread sources +.PATH: ${.CURDIR}/uthread + +SRCS+= \ + uthread_accept.c \ + uthread_acl_delete_fd.c \ + uthread_acl_get_fd.c \ + uthread_acl_set_fd.c \ + uthread_acl_aclcheck_fd.c \ + uthread_aio_suspend.c \ + uthread_attr_destroy.c \ + uthread_attr_init.c \ + uthread_attr_getdetachstate.c \ + uthread_attr_getguardsize.c \ + uthread_attr_getinheritsched.c \ + uthread_attr_getschedparam.c \ + uthread_attr_getschedpolicy.c \ + uthread_attr_getscope.c \ + uthread_attr_getstackaddr.c \ + uthread_attr_getstacksize.c \ + uthread_attr_setcreatesuspend_np.c \ + uthread_attr_setdetachstate.c \ + uthread_attr_setguardsize.c \ + uthread_attr_setinheritsched.c \ + uthread_attr_setschedparam.c \ + uthread_attr_setschedpolicy.c \ + uthread_attr_setscope.c \ + uthread_attr_setstackaddr.c \ + uthread_attr_setstacksize.c \ + uthread_autoinit.cc \ + uthread_bind.c \ + uthread_cancel.c \ + uthread_cap_get_fd.c \ + uthread_cap_set_fd.c \ + uthread_clean.c \ + uthread_close.c \ + uthread_cond.c \ + uthread_condattr_destroy.c \ + uthread_condattr_init.c \ + uthread_connect.c \ + uthread_creat.c \ + uthread_create.c \ + uthread_detach.c \ + uthread_dup.c \ + uthread_dup2.c \ + uthread_equal.c \ + uthread_execve.c \ + uthread_exit.c \ + uthread_fchflags.c \ + uthread_fchmod.c \ + uthread_fchown.c \ + uthread_fcntl.c \ + uthread_fd.c \ + uthread_file.c \ + uthread_find_thread.c \ + uthread_flock.c \ + uthread_fork.c \ + uthread_fpathconf.c \ + uthread_fstat.c \ + uthread_fstatfs.c \ + uthread_fsync.c \ + uthread_gc.c \ + uthread_getdirentries.c \ + uthread_getpeername.c \ + uthread_getprio.c \ + uthread_getschedparam.c \ + uthread_getsockname.c \ + uthread_getsockopt.c \ + uthread_info.c \ + uthread_init.c \ + uthread_ioctl.c \ + uthread_jmp.c \ + uthread_join.c \ + uthread_kern.c \ + uthread_kevent.c \ + uthread_kill.c \ + uthread_listen.c \ + uthread_main_np.c \ + uthread_mattr_init.c \ + uthread_mattr_kind_np.c \ + uthread_msync.c \ + uthread_multi_np.c \ + uthread_mutex.c \ + uthread_mutex_prioceiling.c \ + uthread_mutex_protocol.c \ + uthread_mutexattr_destroy.c \ + uthread_nanosleep.c \ + uthread_once.c \ + uthread_open.c \ + uthread_pause.c \ + uthread_pipe.c \ + uthread_poll.c \ + uthread_priority_queue.c \ + uthread_read.c \ + uthread_readv.c \ + uthread_recvfrom.c \ + uthread_recvmsg.c \ + uthread_resume_np.c \ + uthread_rwlock.c \ + uthread_rwlockattr.c \ + uthread_select.c \ + uthread_self.c \ + uthread_sem.c \ + uthread_sendfile.c \ + uthread_sendmsg.c \ + uthread_sendto.c \ + uthread_seterrno.c \ + uthread_setprio.c \ + uthread_setschedparam.c \ + uthread_setsockopt.c \ + uthread_shutdown.c \ + uthread_sig.c \ + uthread_sigaction.c \ + uthread_sigmask.c \ + uthread_sigpending.c \ + uthread_sigprocmask.c \ + uthread_sigsuspend.c \ + uthread_sigwait.c \ + uthread_single_np.c \ + uthread_sleep.c \ + uthread_socket.c \ + uthread_socketpair.c \ + uthread_spec.c \ + uthread_spinlock.c \ + uthread_stack.c \ + uthread_suspend_np.c \ + uthread_switch_np.c \ + uthread_system.c \ + uthread_tcdrain.c \ + uthread_vfork.c \ + uthread_wait.c \ + uthread_wait4.c \ + uthread_waitpid.c \ + uthread_write.c \ + uthread_writev.c \ + uthread_yield.c diff --git a/lib/libc_r/uthread/pthread_private.h b/lib/libc_r/uthread/pthread_private.h new file mode 100644 index 0000000..ec15c3a --- /dev/null +++ b/lib/libc_r/uthread/pthread_private.h @@ -0,0 +1,1362 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * Private thread definitions for the uthread kernel. + * + * $FreeBSD$ + */ + +#ifndef _PTHREAD_PRIVATE_H +#define _PTHREAD_PRIVATE_H + +/* + * Evaluate the storage class specifier. + */ +#ifdef GLOBAL_PTHREAD_PRIVATE +#define SCLASS +#else +#define SCLASS extern +#endif + +/* + * Include files. + */ +#include <setjmp.h> +#include <signal.h> +#include <stdio.h> +#include <sys/queue.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/cdefs.h> +#include <sched.h> +#include <spinlock.h> +#include <ucontext.h> +#include <pthread_np.h> + +/* + * Define machine dependent macros to get and set the stack pointer + * from the supported contexts. Also define a macro to set the return + * address in a jmp_buf context. + * + * XXX - These need to be moved into architecture dependent support files. + */ +#if defined(__i386__) +#define GET_STACK_JB(jb) ((unsigned long)((jb)[0]._jb[2])) +#define GET_STACK_SJB(sjb) ((unsigned long)((sjb)[0]._sjb[2])) +#define GET_STACK_UC(ucp) ((unsigned long)((ucp)->uc_mcontext.mc_esp)) +#define SET_STACK_JB(jb, stk) (jb)[0]._jb[2] = (int)(stk) +#define SET_STACK_SJB(sjb, stk) (sjb)[0]._sjb[2] = (int)(stk) +#define SET_STACK_UC(ucp, stk) (ucp)->uc_mcontext.mc_esp = (int)(stk) +#define FP_SAVE_UC(ucp) do { \ + char *fdata; \ + fdata = (char *) (ucp)->uc_mcontext.mc_fpregs; \ + __asm__("fnsave %0": :"m"(*fdata)); \ +} while (0) +#define FP_RESTORE_UC(ucp) do { \ + char *fdata; \ + fdata = (char *) (ucp)->uc_mcontext.mc_fpregs; \ + __asm__("frstor %0": :"m"(*fdata)); \ +} while (0) +#define SET_RETURN_ADDR_JB(jb, ra) (jb)[0]._jb[0] = (int)(ra) +#elif defined(__alpha__) +#include <machine/reg.h> +#define GET_STACK_JB(jb) ((unsigned long)((jb)[0]._jb[R_SP + 4])) +#define GET_STACK_SJB(sjb) ((unsigned long)((sjb)[0]._sjb[R_SP + 4])) +#define GET_STACK_UC(ucp) ((ucp)->uc_mcontext.mc_regs[R_SP]) +#define SET_STACK_JB(jb, stk) (jb)[0]._jb[R_SP + 4] = (long)(stk) +#define SET_STACK_SJB(sjb, stk) (sjb)[0]._sjb[R_SP + 4] = (long)(stk) +#define SET_STACK_UC(ucp, stk) (ucp)->uc_mcontext.mc_regs[R_SP] = (unsigned long)(stk) +#define FP_SAVE_UC(ucp) +#define FP_RESTORE_UC(ucp) +#define SET_RETURN_ADDR_JB(jb, ra) do { \ + (jb)[0]._jb[2] = (long)(ra); \ + (jb)[0]._jb[R_RA + 4] = (long)(ra); \ + (jb)[0]._jb[R_T12 + 4] = (long)(ra); \ +} while (0) +#else +#error "Don't recognize this architecture!" +#endif + +/* + * Kernel fatal error handler macro. + */ +#define PANIC(string) _thread_exit(__FILE__,__LINE__,string) + + +/* Output debug messages like this: */ +#define stdout_debug(args...) do { \ + char buf[128]; \ + snprintf(buf, sizeof(buf), ##args); \ + __sys_write(1, buf, strlen(buf)); \ +} while (0) +#define stderr_debug(args...) do { \ + char buf[128]; \ + snprintf(buf, sizeof(buf), ##args); \ + __sys_write(2, buf, strlen(buf)); \ +} while (0) + + + +/* + * Priority queue manipulation macros (using pqe link): + */ +#define PTHREAD_PRIOQ_INSERT_HEAD(thrd) _pq_insert_head(&_readyq,thrd) +#define PTHREAD_PRIOQ_INSERT_TAIL(thrd) _pq_insert_tail(&_readyq,thrd) +#define PTHREAD_PRIOQ_REMOVE(thrd) _pq_remove(&_readyq,thrd) +#define PTHREAD_PRIOQ_FIRST() _pq_first(&_readyq) + +/* + * Waiting queue manipulation macros (using pqe link): + */ +#define PTHREAD_WAITQ_REMOVE(thrd) _waitq_remove(thrd) +#define PTHREAD_WAITQ_INSERT(thrd) _waitq_insert(thrd) + +#if defined(_PTHREADS_INVARIANTS) +#define PTHREAD_WAITQ_CLEARACTIVE() _waitq_clearactive() +#define PTHREAD_WAITQ_SETACTIVE() _waitq_setactive() +#else +#define PTHREAD_WAITQ_CLEARACTIVE() +#define PTHREAD_WAITQ_SETACTIVE() +#endif + +/* + * Work queue manipulation macros (using qe link): + */ +#define PTHREAD_WORKQ_INSERT(thrd) do { \ + TAILQ_INSERT_TAIL(&_workq,thrd,qe); \ + (thrd)->flags |= PTHREAD_FLAGS_IN_WORKQ; \ +} while (0) +#define PTHREAD_WORKQ_REMOVE(thrd) do { \ + TAILQ_REMOVE(&_workq,thrd,qe); \ + (thrd)->flags &= ~PTHREAD_FLAGS_IN_WORKQ; \ +} while (0) + + +/* + * State change macro without scheduling queue change: + */ +#define PTHREAD_SET_STATE(thrd, newstate) do { \ + (thrd)->state = newstate; \ + (thrd)->fname = __FILE__; \ + (thrd)->lineno = __LINE__; \ +} while (0) + +/* + * State change macro with scheduling queue change - This must be + * called with preemption deferred (see thread_kern_sched_[un]defer). + */ +#if defined(_PTHREADS_INVARIANTS) +#include <assert.h> +#define PTHREAD_ASSERT(cond, msg) do { \ + if (!(cond)) \ + PANIC(msg); \ +} while (0) +#define PTHREAD_ASSERT_NOT_IN_SYNCQ(thrd) \ + PTHREAD_ASSERT((((thrd)->flags & PTHREAD_FLAGS_IN_SYNCQ) == 0), \ + "Illegal call from signal handler"); +#define PTHREAD_NEW_STATE(thrd, newstate) do { \ + if (_thread_kern_new_state != 0) \ + PANIC("Recursive PTHREAD_NEW_STATE"); \ + _thread_kern_new_state = 1; \ + if ((thrd)->state != newstate) { \ + if ((thrd)->state == PS_RUNNING) { \ + PTHREAD_PRIOQ_REMOVE(thrd); \ + PTHREAD_WAITQ_INSERT(thrd); \ + } else if (newstate == PS_RUNNING) { \ + PTHREAD_WAITQ_REMOVE(thrd); \ + PTHREAD_PRIOQ_INSERT_TAIL(thrd); \ + } \ + } \ + _thread_kern_new_state = 0; \ + PTHREAD_SET_STATE(thrd, newstate); \ +} while (0) +#else +#define PTHREAD_ASSERT(cond, msg) +#define PTHREAD_ASSERT_NOT_IN_SYNCQ(thrd) +#define PTHREAD_NEW_STATE(thrd, newstate) do { \ + if ((thrd)->state != newstate) { \ + if ((thrd)->state == PS_RUNNING) { \ + PTHREAD_PRIOQ_REMOVE(thrd); \ + PTHREAD_WAITQ_INSERT(thrd); \ + } else if (newstate == PS_RUNNING) { \ + PTHREAD_WAITQ_REMOVE(thrd); \ + PTHREAD_PRIOQ_INSERT_TAIL(thrd); \ + } \ + } \ + PTHREAD_SET_STATE(thrd, newstate); \ +} while (0) +#endif + +/* + * Define the signals to be used for scheduling. + */ +#if defined(_PTHREADS_COMPAT_SCHED) +#define _ITIMER_SCHED_TIMER ITIMER_VIRTUAL +#define _SCHED_SIGNAL SIGVTALRM +#else +#define _ITIMER_SCHED_TIMER ITIMER_PROF +#define _SCHED_SIGNAL SIGPROF +#endif + +/* + * Priority queues. + * + * XXX It'd be nice if these were contained in uthread_priority_queue.[ch]. + */ +typedef struct pq_list { + TAILQ_HEAD(, pthread) pl_head; /* list of threads at this priority */ + TAILQ_ENTRY(pq_list) pl_link; /* link for queue of priority lists */ + int pl_prio; /* the priority of this list */ + int pl_queued; /* is this in the priority queue */ +} pq_list_t; + +typedef struct pq_queue { + TAILQ_HEAD(, pq_list) pq_queue; /* queue of priority lists */ + pq_list_t *pq_lists; /* array of all priority lists */ + int pq_size; /* number of priority lists */ +} pq_queue_t; + + +/* + * TailQ initialization values. + */ +#define TAILQ_INITIALIZER { NULL, NULL } + +/* + * Mutex definitions. + */ +union pthread_mutex_data { + void *m_ptr; + int m_count; +}; + +struct pthread_mutex { + enum pthread_mutextype m_type; + int m_protocol; + TAILQ_HEAD(mutex_head, pthread) m_queue; + struct pthread *m_owner; + union pthread_mutex_data m_data; + long m_flags; + int m_refcount; + + /* + * Used for priority inheritence and protection. + * + * m_prio - For priority inheritence, the highest active + * priority (threads locking the mutex inherit + * this priority). For priority protection, the + * ceiling priority of this mutex. + * m_saved_prio - mutex owners inherited priority before + * taking the mutex, restored when the owner + * unlocks the mutex. + */ + int m_prio; + int m_saved_prio; + + /* + * Link for list of all mutexes a thread currently owns. + */ + TAILQ_ENTRY(pthread_mutex) m_qe; + + /* + * Lock for accesses to this structure. + */ + spinlock_t lock; +}; + +/* + * 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_STATIC_INITIALIZER \ + { PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, TAILQ_INITIALIZER, \ + NULL, { NULL }, MUTEX_FLAGS_PRIVATE, 0, 0, 0, TAILQ_INITIALIZER, \ + _SPINLOCK_INITIALIZER } + +struct pthread_mutex_attr { + enum pthread_mutextype m_type; + int m_protocol; + int m_ceiling; + long m_flags; +}; + +#define PTHREAD_MUTEXATTR_STATIC_INITIALIZER \ + { PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, 0, MUTEX_FLAGS_PRIVATE } + +/* + * Condition variable definitions. + */ +enum pthread_cond_type { + COND_TYPE_FAST, + COND_TYPE_MAX +}; + +struct pthread_cond { + enum pthread_cond_type c_type; + TAILQ_HEAD(cond_head, pthread) c_queue; + pthread_mutex_t c_mutex; + void *c_data; + long c_flags; + int c_seqno; + + /* + * Lock for accesses to this structure. + */ + spinlock_t lock; +}; + +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_STATIC_INITIALIZER \ + { COND_TYPE_FAST, TAILQ_INITIALIZER, NULL, NULL, \ + 0, 0, _SPINLOCK_INITIALIZER } + +/* + * Semaphore definitions. + */ +struct sem { +#define SEM_MAGIC ((u_int32_t) 0x09fa4012) + u_int32_t magic; + pthread_mutex_t lock; + pthread_cond_t gtzero; + u_int32_t count; + u_int32_t nwaiters; +}; + +/* + * Cleanup definitions. + */ +struct pthread_cleanup { + struct pthread_cleanup *next; + void (*routine) (); + void *routine_arg; +}; + +struct pthread_attr { + int sched_policy; + int sched_inherit; + int sched_interval; + int prio; + int suspend; + int flags; + void *arg_attr; + void (*cleanup_attr) (); + void *stackaddr_attr; + size_t stacksize_attr; + size_t guardsize_attr; +}; + +/* + * Thread creation state attributes. + */ +#define PTHREAD_CREATE_RUNNING 0 +#define PTHREAD_CREATE_SUSPENDED 1 + +/* + * Additional state for a thread suspended with pthread_suspend_np(). + */ +enum pthread_susp { + SUSP_NO, /* Not suspended. */ + SUSP_YES, /* Suspended. */ + SUSP_JOIN, /* Suspended, joining. */ + SUSP_NOWAIT, /* Suspended, was in a mutex or condition queue. */ + SUSP_MUTEX_WAIT,/* Suspended, still in a mutex queue. */ + SUSP_COND_WAIT /* Suspended, still in a condition queue. */ +}; + +/* + * Miscellaneous definitions. + */ +#define PTHREAD_STACK_DEFAULT 65536 +/* + * Size of default red zone at the end of each stack. In actuality, this "red + * zone" is merely an unmapped region, except in the case of the initial stack. + * Since mmap() makes it possible to specify the maximum growth of a MAP_STACK + * region, an unmapped gap between thread stacks achieves the same effect as + * explicitly mapped red zones. + */ +#define PTHREAD_GUARD_DEFAULT PAGE_SIZE + +/* + * Maximum size of initial thread's stack. This perhaps deserves to be larger + * than the stacks of other threads, since many applications are likely to run + * almost entirely on this stack. + */ +#define PTHREAD_STACK_INITIAL 0x100000 + +/* Size of the scheduler stack: */ +#define SCHED_STACK_SIZE PAGE_SIZE + +/* + * Define the different priority ranges. All applications have thread + * priorities constrained within 0-31. The threads library raises the + * priority when delivering signals in order to ensure that signal + * delivery happens (from the POSIX spec) "as soon as possible". + * In the future, the threads library will also be able to map specific + * threads into real-time (cooperating) processes or kernel threads. + * The RT and SIGNAL priorities will be used internally and added to + * thread base priorities so that the scheduling queue can handle both + * normal and RT priority threads with and without signal handling. + * + * The approach taken is that, within each class, signal delivery + * always has priority over thread execution. + */ +#define PTHREAD_DEFAULT_PRIORITY 15 +#define PTHREAD_MIN_PRIORITY 0 +#define PTHREAD_MAX_PRIORITY 31 /* 0x1F */ +#define PTHREAD_SIGNAL_PRIORITY 32 /* 0x20 */ +#define PTHREAD_RT_PRIORITY 64 /* 0x40 */ +#define PTHREAD_FIRST_PRIORITY PTHREAD_MIN_PRIORITY +#define PTHREAD_LAST_PRIORITY \ + (PTHREAD_MAX_PRIORITY + PTHREAD_SIGNAL_PRIORITY + PTHREAD_RT_PRIORITY) +#define PTHREAD_BASE_PRIORITY(prio) ((prio) & PTHREAD_MAX_PRIORITY) + +/* + * Clock resolution in microseconds. + */ +#define CLOCK_RES_USEC 10000 +#define CLOCK_RES_USEC_MIN 1000 + +/* + * Time slice period in microseconds. + */ +#define TIMESLICE_USEC 20000 + +/* + * Define a thread-safe macro to get the current time of day + * which is updated at regular intervals by the scheduling signal + * handler. + */ +#define GET_CURRENT_TOD(tv) \ + do { \ + tv.tv_sec = _sched_tod.tv_sec; \ + tv.tv_usec = _sched_tod.tv_usec; \ + } while (tv.tv_sec != _sched_tod.tv_sec) + + +struct pthread_rwlockattr { + int pshared; +}; + +struct pthread_rwlock { + pthread_mutex_t lock; /* monitor lock */ + int state; /* 0 = idle >0 = # of readers -1 = writer */ + pthread_cond_t read_signal; + pthread_cond_t write_signal; + int blocked_writers; +}; + +/* + * Thread states. + */ +enum pthread_state { + PS_RUNNING, + PS_SIGTHREAD, + PS_MUTEX_WAIT, + PS_COND_WAIT, + PS_FDLR_WAIT, + PS_FDLW_WAIT, + PS_FDR_WAIT, + PS_FDW_WAIT, + PS_FILE_WAIT, + PS_POLL_WAIT, + PS_SELECT_WAIT, + PS_SLEEP_WAIT, + PS_WAIT_WAIT, + PS_SIGSUSPEND, + PS_SIGWAIT, + PS_SPINBLOCK, + PS_JOIN, + PS_SUSPENDED, + PS_DEAD, + PS_DEADLOCK, + PS_STATE_MAX +}; + + +/* + * File descriptor locking definitions. + */ +#define FD_READ 0x1 +#define FD_WRITE 0x2 +#define FD_RDWR (FD_READ | FD_WRITE) + +/* + * File descriptor table structure. + */ +struct fd_table_entry { + /* + * Lock for accesses to this file descriptor table + * entry. This is passed to _spinlock() to provide atomic + * access to this structure. It does *not* represent the + * state of the lock on the file descriptor. + */ + spinlock_t lock; + TAILQ_HEAD(, pthread) r_queue; /* Read queue. */ + TAILQ_HEAD(, pthread) w_queue; /* Write queue. */ + struct pthread *r_owner; /* Ptr to thread owning read lock. */ + struct pthread *w_owner; /* Ptr to thread owning write lock. */ + char *r_fname; /* Ptr to read lock source file name */ + int r_lineno; /* Read lock source line number. */ + char *w_fname; /* Ptr to write lock source file name */ + int w_lineno; /* Write lock source line number. */ + int r_lockcount; /* Count for FILE read locks. */ + int w_lockcount; /* Count for FILE write locks. */ + int flags; /* Flags used in open. */ +}; + +struct pthread_poll_data { + int nfds; + struct pollfd *fds; +}; + +union pthread_wait_data { + pthread_mutex_t mutex; + pthread_cond_t cond; + const sigset_t *sigwait; /* Waiting on a signal in sigwait */ + struct { + short fd; /* Used when thread waiting on fd */ + short branch; /* Line number, for debugging. */ + char *fname; /* Source file name for debugging.*/ + } fd; + FILE *fp; + struct pthread_poll_data *poll_data; + spinlock_t *spinlock; + struct pthread *thread; +}; + +/* + * Define a continuation routine that can be used to perform a + * transfer of control: + */ +typedef void (*thread_continuation_t) (void *); + +struct pthread_signal_frame; + +struct pthread_state_data { + struct pthread_signal_frame *psd_curframe; + sigset_t psd_sigmask; + struct timespec psd_wakeup_time; + union pthread_wait_data psd_wait_data; + enum pthread_state psd_state; + int psd_flags; + int psd_interrupted; + int psd_longjmp_val; + int psd_sigmask_seqno; + int psd_signo; + int psd_sig_defer_count; + /* XXX - What about thread->timeout and/or thread->error? */ +}; + +struct join_status { + struct pthread *thread; + void *ret; + int error; +}; + +/* + * The frame that is added to the top of a threads stack when setting up + * up the thread to run a signal handler. + */ +struct pthread_signal_frame { + /* + * This stores the threads state before the signal. + */ + struct pthread_state_data saved_state; + + /* + * Threads return context; we use only jmp_buf's for now. + */ + union { + jmp_buf jb; + ucontext_t uc; + } ctx; + int signo; /* signal, arg 1 to sighandler */ + int sig_has_args; /* use signal args if true */ + ucontext_t uc; + siginfo_t siginfo; +}; + +struct pthread_specific_elem { + const void *data; + int seqno; +}; + +/* + * Thread structure. + */ +struct pthread { + /* + * Magic value to help recognize a valid thread structure + * from an invalid one: + */ +#define PTHREAD_MAGIC ((u_int32_t) 0xd09ba115) + u_int32_t magic; + char *name; + u_int64_t uniqueid; /* for gdb */ + + /* + * Lock for accesses to this thread structure. + */ + spinlock_t lock; + + /* Queue entry for list of all threads: */ + TAILQ_ENTRY(pthread) tle; + + /* Queue entry for list of dead threads: */ + TAILQ_ENTRY(pthread) dle; + + /* + * Thread start routine, argument, stack pointer and thread + * attributes. + */ + void *(*start_routine)(void *); + void *arg; + void *stack; + struct pthread_attr attr; + + /* + * Threads return context; we use only jmp_buf's for now. + */ + union { + jmp_buf jb; + ucontext_t uc; + } ctx; + + /* + * Used for tracking delivery of signal handlers. + */ + struct pthread_signal_frame *curframe; + + /* + * Cancelability flags - the lower 2 bits are used by cancel + * definitions in pthread.h + */ +#define PTHREAD_AT_CANCEL_POINT 0x0004 +#define PTHREAD_CANCELLING 0x0008 +#define PTHREAD_CANCEL_NEEDED 0x0010 + int cancelflags; + + enum pthread_susp suspended; + + thread_continuation_t continuation; + + /* + * Current signal mask and pending signals. + */ + sigset_t sigmask; + sigset_t sigpend; + int sigmask_seqno; + int check_pending; + + /* Thread state: */ + enum pthread_state state; + + /* Scheduling clock when this thread was last made active. */ + long last_active; + + /* Scheduling clock when this thread was last made inactive. */ + long last_inactive; + + /* + * Number of microseconds accumulated by this thread when + * time slicing is active. + */ + long slice_usec; + + /* + * Time to wake up thread. This is used for sleeping threads and + * for any operation which may time out (such as select). + */ + struct timespec wakeup_time; + + /* TRUE if operation has timed out. */ + int timeout; + + /* + * Error variable used instead of errno. The function __error() + * returns a pointer to this. + */ + int error; + + /* + * The joiner is the thread that is joining to this thread. The + * join status keeps track of a join operation to another thread. + */ + struct pthread *joiner; + struct join_status join_status; + + /* + * The current thread can belong to only one scheduling queue at + * a time (ready or waiting queue). It can also belong to: + * + * o A queue of threads waiting for a mutex + * o A queue of threads waiting for a condition variable + * o A queue of threads waiting for a file descriptor lock + * o A queue of threads needing work done by the kernel thread + * (waiting for a spinlock or file I/O) + * + * A thread can also be joining a thread (the joiner field above). + * + * It must not be possible for a thread to belong to any of the + * above queues while it is handling a signal. Signal handlers + * may longjmp back to previous stack frames circumventing normal + * control flow. This could corrupt queue integrity if the thread + * retains membership in the queue. Therefore, if a thread is a + * member of one of these queues when a signal handler is invoked, + * it must remove itself from the queue before calling the signal + * handler and reinsert itself after normal return of the handler. + * + * Use pqe for the scheduling queue link (both ready and waiting), + * sqe for synchronization (mutex and condition variable) queue + * links, and qe for all other links. + */ + TAILQ_ENTRY(pthread) pqe; /* priority queue link */ + TAILQ_ENTRY(pthread) sqe; /* synchronization queue link */ + TAILQ_ENTRY(pthread) qe; /* all other queues link */ + + /* Wait data. */ + union pthread_wait_data data; + + /* + * Allocated for converting select into poll. + */ + struct pthread_poll_data poll_data; + + /* + * Set to TRUE if a blocking operation was + * interrupted by a signal: + */ + int interrupted; + + /* Signal number when in state PS_SIGWAIT: */ + int signo; + + /* + * Set to non-zero when this thread has deferred signals. + * We allow for recursive deferral. + */ + int sig_defer_count; + + /* + * Set to TRUE if this thread should yield after undeferring + * signals. + */ + int yield_on_sig_undefer; + + /* Miscellaneous flags; only set with signals deferred. */ + int flags; +#define PTHREAD_FLAGS_PRIVATE 0x0001 +#define PTHREAD_EXITING 0x0002 +#define PTHREAD_FLAGS_IN_WAITQ 0x0004 /* in waiting queue using pqe link */ +#define PTHREAD_FLAGS_IN_PRIOQ 0x0008 /* in priority queue using pqe link */ +#define PTHREAD_FLAGS_IN_WORKQ 0x0010 /* in work queue using qe link */ +#define PTHREAD_FLAGS_IN_FILEQ 0x0020 /* in file lock queue using qe link */ +#define PTHREAD_FLAGS_IN_FDQ 0x0040 /* in fd lock queue using qe link */ +#define PTHREAD_FLAGS_IN_CONDQ 0x0080 /* in condition queue using sqe link*/ +#define PTHREAD_FLAGS_IN_MUTEXQ 0x0100 /* in mutex queue using sqe link */ +#define PTHREAD_FLAGS_TRACE 0x0200 /* for debugging purposes */ +#define PTHREAD_FLAGS_IN_SYNCQ \ + (PTHREAD_FLAGS_IN_CONDQ | PTHREAD_FLAGS_IN_MUTEXQ) + + /* + * Base priority is the user setable and retrievable priority + * of the thread. It is only affected by explicit calls to + * set thread priority and upon thread creation via a thread + * attribute or default priority. + */ + char base_priority; + + /* + * Inherited priority is the priority a thread inherits by + * taking a priority inheritence or protection mutex. It + * is not affected by base priority changes. Inherited + * priority defaults to and remains 0 until a mutex is taken + * that is being waited on by any other thread whose priority + * is non-zero. + */ + char inherited_priority; + + /* + * Active priority is always the maximum of the threads base + * priority and inherited priority. When there is a change + * in either the base or inherited priority, the active + * priority must be recalculated. + */ + char active_priority; + + /* Number of priority ceiling or protection mutexes owned. */ + int priority_mutex_count; + + /* + * Queue of currently owned mutexes. + */ + TAILQ_HEAD(, pthread_mutex) mutexq; + + void *ret; + struct pthread_specific_elem *specific; + int specific_data_count; + + /* Cleanup handlers Link List */ + struct pthread_cleanup *cleanup; + char *fname; /* Ptr to source file name */ + int lineno; /* Source line number. */ +}; + +/* + * Global variables for the uthread kernel. + */ + +SCLASS void *_usrstack +#ifdef GLOBAL_PTHREAD_PRIVATE += (void *) USRSTACK; +#else +; +#endif + +/* Kernel thread structure used when there are no running threads: */ +SCLASS struct pthread _thread_kern_thread; + +/* Ptr to the thread structure for the running thread: */ +SCLASS struct pthread * volatile _thread_run +#ifdef GLOBAL_PTHREAD_PRIVATE += &_thread_kern_thread; +#else +; +#endif + +/* Ptr to the thread structure for the last user thread to run: */ +SCLASS struct pthread * volatile _last_user_thread +#ifdef GLOBAL_PTHREAD_PRIVATE += &_thread_kern_thread; +#else +; +#endif + +/* + * Ptr to the thread running in single-threaded mode or NULL if + * running multi-threaded (default POSIX behaviour). + */ +SCLASS struct pthread * volatile _thread_single +#ifdef GLOBAL_PTHREAD_PRIVATE += NULL; +#else +; +#endif + +/* List of all threads: */ +SCLASS TAILQ_HEAD(, pthread) _thread_list +#ifdef GLOBAL_PTHREAD_PRIVATE += TAILQ_HEAD_INITIALIZER(_thread_list); +#else +; +#endif + +/* + * Array of kernel pipe file descriptors that are used to ensure that + * no signals are missed in calls to _select. + */ +SCLASS int _thread_kern_pipe[2] +#ifdef GLOBAL_PTHREAD_PRIVATE += { + -1, + -1 +}; +#else +; +#endif +SCLASS int volatile _queue_signals +#ifdef GLOBAL_PTHREAD_PRIVATE += 0; +#else +; +#endif +SCLASS int _thread_kern_in_sched +#ifdef GLOBAL_PTHREAD_PRIVATE += 0; +#else +; +#endif + +SCLASS int _sig_in_handler +#ifdef GLOBAL_PTHREAD_PRIVATE += 0; +#else +; +#endif + +/* Time of day at last scheduling timer signal: */ +SCLASS struct timeval volatile _sched_tod +#ifdef GLOBAL_PTHREAD_PRIVATE += { 0, 0 }; +#else +; +#endif + +/* + * Current scheduling timer ticks; used as resource usage. + */ +SCLASS unsigned int volatile _sched_ticks +#ifdef GLOBAL_PTHREAD_PRIVATE += 0; +#else +; +#endif + +/* Dead threads: */ +SCLASS TAILQ_HEAD(, pthread) _dead_list +#ifdef GLOBAL_PTHREAD_PRIVATE += TAILQ_HEAD_INITIALIZER(_dead_list); +#else +; +#endif + +/* Initial thread: */ +SCLASS struct pthread *_thread_initial +#ifdef GLOBAL_PTHREAD_PRIVATE += NULL; +#else +; +#endif + +/* Default thread attributes: */ +SCLASS struct pthread_attr pthread_attr_default +#ifdef GLOBAL_PTHREAD_PRIVATE += { SCHED_RR, 0, TIMESLICE_USEC, PTHREAD_DEFAULT_PRIORITY, + PTHREAD_CREATE_RUNNING, PTHREAD_CREATE_JOINABLE, NULL, NULL, NULL, + PTHREAD_STACK_DEFAULT, PTHREAD_GUARD_DEFAULT }; +#else +; +#endif + +/* Default mutex attributes: */ +SCLASS struct pthread_mutex_attr pthread_mutexattr_default +#ifdef GLOBAL_PTHREAD_PRIVATE += { PTHREAD_MUTEX_DEFAULT, PTHREAD_PRIO_NONE, 0, 0 }; +#else +; +#endif + +/* Default condition variable attributes: */ +SCLASS struct pthread_cond_attr pthread_condattr_default +#ifdef GLOBAL_PTHREAD_PRIVATE += { COND_TYPE_FAST, 0 }; +#else +; +#endif + +/* + * Standard I/O file descriptors need special flag treatment since + * setting one to non-blocking does all on *BSD. Sigh. This array + * is used to store the initial flag settings. + */ +SCLASS int _pthread_stdio_flags[3]; + +/* File table information: */ +SCLASS struct fd_table_entry **_thread_fd_table +#ifdef GLOBAL_PTHREAD_PRIVATE += NULL; +#else +; +#endif + +/* Table for polling file descriptors: */ +SCLASS struct pollfd *_thread_pfd_table +#ifdef GLOBAL_PTHREAD_PRIVATE += NULL; +#else +; +#endif + +SCLASS const int dtablecount +#ifdef GLOBAL_PTHREAD_PRIVATE += 4096/sizeof(struct fd_table_entry); +#else +; +#endif +SCLASS int _thread_dtablesize /* Descriptor table size. */ +#ifdef GLOBAL_PTHREAD_PRIVATE += 0; +#else +; +#endif + +SCLASS int _clock_res_usec /* Clock resolution in usec. */ +#ifdef GLOBAL_PTHREAD_PRIVATE += CLOCK_RES_USEC; +#else +; +#endif + +/* Garbage collector mutex and condition variable. */ +SCLASS pthread_mutex_t _gc_mutex +#ifdef GLOBAL_PTHREAD_PRIVATE += NULL +#endif +; +SCLASS pthread_cond_t _gc_cond +#ifdef GLOBAL_PTHREAD_PRIVATE += NULL +#endif +; + +/* + * Array of signal actions for this process. + */ +SCLASS struct sigaction _thread_sigact[NSIG]; + +/* + * Array of counts of dummy handlers for SIG_DFL signals. This is used to + * assure that there is always a dummy signal handler installed while there is a + * thread sigwait()ing on the corresponding signal. + */ +SCLASS int _thread_dfl_count[NSIG]; + +/* + * Pending signals and mask for this process: + */ +SCLASS sigset_t _process_sigpending; +SCLASS sigset_t _process_sigmask +#ifdef GLOBAL_PTHREAD_PRIVATE += { {0, 0, 0, 0} } +#endif +; + +/* + * Scheduling queues: + */ +SCLASS pq_queue_t _readyq; +SCLASS TAILQ_HEAD(, pthread) _waitingq; + +/* + * Work queue: + */ +SCLASS TAILQ_HEAD(, pthread) _workq; + +/* Tracks the number of threads blocked while waiting for a spinlock. */ +SCLASS volatile int _spinblock_count +#ifdef GLOBAL_PTHREAD_PRIVATE += 0 +#endif +; + +/* Used to maintain pending and active signals: */ +struct sigstatus { + int pending; /* Is this a pending signal? */ + int blocked; /* + * A handler is currently active for + * this signal; ignore subsequent + * signals until the handler is done. + */ + int signo; /* arg 1 to signal handler */ + siginfo_t siginfo; /* arg 2 to signal handler */ + ucontext_t uc; /* arg 3 to signal handler */ +}; + +SCLASS struct sigstatus _thread_sigq[NSIG]; + +/* Indicates that the signal queue needs to be checked. */ +SCLASS volatile int _sigq_check_reqd +#ifdef GLOBAL_PTHREAD_PRIVATE += 0 +#endif +; + +/* Thread switch hook. */ +SCLASS pthread_switch_routine_t _sched_switch_hook +#ifdef GLOBAL_PTHREAD_PRIVATE += NULL +#endif +; + +/* + * Declare the kernel scheduler jump buffer and stack: + */ +SCLASS jmp_buf _thread_kern_sched_jb; + +SCLASS void * _thread_kern_sched_stack +#ifdef GLOBAL_PTHREAD_PRIVATE += NULL +#endif +; + + +/* Used for _PTHREADS_INVARIANTS checking. */ +SCLASS int _thread_kern_new_state +#ifdef GLOBAL_PTHREAD_PRIVATE += 0 +#endif +; + +/* Undefine the storage class specifier: */ +#undef SCLASS + +#ifdef _LOCK_DEBUG +#define _FD_LOCK(_fd,_type,_ts) _thread_fd_lock_debug(_fd, _type, \ + _ts, __FILE__, __LINE__) +#define _FD_UNLOCK(_fd,_type) _thread_fd_unlock_debug(_fd, _type, \ + __FILE__, __LINE__) +#else +#define _FD_LOCK(_fd,_type,_ts) _thread_fd_lock(_fd, _type, _ts) +#define _FD_UNLOCK(_fd,_type) _thread_fd_unlock(_fd, _type) +#endif + +/* + * Function prototype definitions. + */ +__BEGIN_DECLS +char *__ttyname_basic(int); +char *__ttyname_r_basic(int, char *, size_t); +char *ttyname_r(int, char *, size_t); +void _cond_wait_backout(pthread_t); +void _fd_lock_backout(pthread_t); +int _find_thread(pthread_t); +struct pthread *_get_curthread(void); +void _set_curthread(struct pthread *); +void *_thread_stack_alloc(size_t, size_t); +void _thread_stack_free(void *, size_t, size_t); +int _thread_create(pthread_t *,const pthread_attr_t *,void *(*start_routine)(void *),void *,pthread_t); +int _thread_fd_lock(int, int, struct timespec *); +int _thread_fd_lock_debug(int, int, struct timespec *,char *fname,int lineno); +int _mutex_cv_lock(pthread_mutex_t *); +int _mutex_cv_unlock(pthread_mutex_t *); +void _mutex_lock_backout(pthread_t); +void _mutex_notify_priochange(pthread_t); +int _mutex_reinit(pthread_mutex_t *); +void _mutex_unlock_private(pthread_t); +int _cond_reinit(pthread_cond_t *); +int _pq_alloc(struct pq_queue *, int, int); +int _pq_init(struct pq_queue *); +void _pq_remove(struct pq_queue *pq, struct pthread *); +void _pq_insert_head(struct pq_queue *pq, struct pthread *); +void _pq_insert_tail(struct pq_queue *pq, struct pthread *); +struct pthread *_pq_first(struct pq_queue *pq); +void *_pthread_getspecific(pthread_key_t); +int _pthread_key_create(pthread_key_t *, void (*) (void *)); +int _pthread_key_delete(pthread_key_t); +int _pthread_mutex_destroy(pthread_mutex_t *); +int _pthread_mutex_init(pthread_mutex_t *, const pthread_mutexattr_t *); +int _pthread_mutex_lock(pthread_mutex_t *); +int _pthread_mutex_trylock(pthread_mutex_t *); +int _pthread_mutex_unlock(pthread_mutex_t *); +int _pthread_mutexattr_init(pthread_mutexattr_t *); +int _pthread_mutexattr_destroy(pthread_mutexattr_t *); +int _pthread_mutexattr_settype(pthread_mutexattr_t *, int); +int _pthread_once(pthread_once_t *, void (*) (void)); +pthread_t _pthread_self(void); +int _pthread_setspecific(pthread_key_t, const void *); +void _waitq_insert(pthread_t pthread); +void _waitq_remove(pthread_t pthread); +#if defined(_PTHREADS_INVARIANTS) +void _waitq_setactive(void); +void _waitq_clearactive(void); +#endif +void _thread_exit(char *, int, char *); +void _thread_exit_cleanup(void); +void _thread_fd_unlock(int, int); +void _thread_fd_unlock_debug(int, int, char *, int); +void _thread_fd_unlock_owned(pthread_t); +void *_thread_cleanup(pthread_t); +void _thread_cleanupspecific(void); +void _thread_dump_info(void); +void _thread_init(void); +void _thread_kern_sched(ucontext_t *); +void _thread_kern_scheduler(void); +void _thread_kern_sched_frame(struct pthread_signal_frame *psf); +void _thread_kern_sched_sig(void); +void _thread_kern_sched_state(enum pthread_state, char *fname, int lineno); +void _thread_kern_sched_state_unlock(enum pthread_state state, + spinlock_t *lock, char *fname, int lineno); +void _thread_kern_set_timeout(const struct timespec *); +void _thread_kern_sig_defer(void); +void _thread_kern_sig_undefer(void); +void _thread_sig_handler(int, siginfo_t *, ucontext_t *); +void _thread_sig_check_pending(struct pthread *pthread); +void _thread_sig_handle_pending(void); +void _thread_sig_send(struct pthread *pthread, int sig); +void _thread_sig_wrapper(void); +void _thread_sigframe_restore(struct pthread *thread, + struct pthread_signal_frame *psf); +void _thread_start(void); +void _thread_seterrno(pthread_t, int); +int _thread_fd_table_init(int fd); +pthread_addr_t _thread_gc(pthread_addr_t); +void _thread_enter_cancellation_point(void); +void _thread_leave_cancellation_point(void); +void _thread_cancellation_point(void); + +/* #include <sys/acl.h> */ +#ifdef _SYS_ACL_H +int __sys___acl_aclcheck_fd(int, acl_type_t, struct acl *); +int __sys___acl_delete_fd(int, acl_type_t); +int __sys___acl_get_fd(int, acl_type_t, struct acl *); +int __sys___acl_set_fd(int, acl_type_t, struct acl *); +#endif + +/* #include <sys/aio.h> */ +#ifdef _SYS_AIO_H_ +int __sys_aio_suspend(const struct aiocb * const[], int, const struct timespec *); +#endif + +/* #include <sys/capability.h> */ +#ifdef _SYS_CAPABILITY_H +int __sys___cap_get_fd(int, struct cap *); +int __sys___cap_set_fd(int, struct cap *); +#endif + +/* #include <sys/event.h> */ +#ifdef _SYS_EVENT_H_ +int __sys_kevent(int, const struct kevent *, int, struct kevent *, + int, const struct timespec *); +#endif + +/* #include <sys/ioctl.h> */ +#ifdef _SYS_IOCTL_H_ +int __sys_ioctl(int, unsigned long, ...); +#endif + +/* #include <sys/mman.h> */ +#ifdef _SYS_MMAN_H_ +int __sys_msync(void *, size_t, int); +#endif + +/* #include <sys/mount.h> */ +#ifdef _SYS_MOUNT_H_ +int __sys_fstatfs(int, struct statfs *); +#endif + +/* #include <sys/socket.h> */ +#ifdef _SYS_SOCKET_H_ +int __sys_accept(int, struct sockaddr *, socklen_t *); +int __sys_bind(int, const struct sockaddr *, socklen_t); +int __sys_connect(int, const struct sockaddr *, socklen_t); +int __sys_getpeername(int, struct sockaddr *, socklen_t *); +int __sys_getsockname(int, struct sockaddr *, socklen_t *); +int __sys_getsockopt(int, int, int, void *, socklen_t *); +int __sys_listen(int, int); +ssize_t __sys_recvfrom(int, void *, size_t, int, struct sockaddr *, socklen_t *); +ssize_t __sys_recvmsg(int, struct msghdr *, int); +int __sys_sendfile(int, int, off_t, size_t, struct sf_hdtr *, off_t *, int); +ssize_t __sys_sendmsg(int, const struct msghdr *, int); +ssize_t __sys_sendto(int, const void *,size_t, int, const struct sockaddr *, socklen_t); +int __sys_setsockopt(int, int, int, const void *, socklen_t); +int __sys_shutdown(int, int); +int __sys_socket(int, int, int); +int __sys_socketpair(int, int, int, int *); +#endif + +/* #include <sys/stat.h> */ +#ifdef _SYS_STAT_H_ +int __sys_fchflags(int, u_long); +int __sys_fchmod(int, mode_t); +int __sys_fstat(int, struct stat *); +#endif + +/* #include <sys/uio.h> */ +#ifdef _SYS_UIO_H_ +ssize_t __sys_readv(int, const struct iovec *, int); +ssize_t __sys_writev(int, const struct iovec *, int); +#endif + +/* #include <sys/wait.h> */ +#ifdef WNOHANG +pid_t __sys_wait4(pid_t, int *, int, struct rusage *); +#endif + +/* #include <dirent.h> */ +#ifdef _DIRENT_H_ +int __sys_getdirentries(int, char *, int, long *); +#endif + +/* #include <fcntl.h> */ +#ifdef _SYS_FCNTL_H_ +int __sys_fcntl(int, int, ...); +int __sys_flock(int, int); +int __sys_open(const char *, int, ...); +#endif + +/* #include <poll.h> */ +#ifdef _SYS_POLL_H_ +int __sys_poll(struct pollfd *, unsigned, int); +#endif + +/* #include <signal.h> */ +#ifdef _SIGNAL_H_ +int __sys_sigaction(int, const struct sigaction *, struct sigaction *); +int __sys_sigaltstack(const struct sigaltstack *, struct sigaltstack *); +int __sys_sigprocmask(int, const sigset_t *, sigset_t *); +int __sys_sigreturn(ucontext_t *); +#endif + +/* #include <unistd.h> */ +#ifdef _UNISTD_H_ +int __sys_close(int); +int __sys_dup(int); +int __sys_dup2(int, int); +int __sys_execve(const char *, char * const *, char * const *); +void __sys_exit(int); +int __sys_fchown(int, uid_t, gid_t); +pid_t __sys_fork(void); +long __sys_fpathconf(int, int); +int __sys_fsync(int); +int __sys_pipe(int *); +ssize_t __sys_read(int, void *, size_t); +ssize_t __sys_write(int, const void *, size_t); +#endif + +/* #include <setjmp.h> */ +#ifdef _SETJMP_H_ +extern void __siglongjmp(sigjmp_buf, int) __dead2; +extern void __longjmp(jmp_buf, int) __dead2; +extern void ___longjmp(jmp_buf, int) __dead2; +#endif +__END_DECLS + +#endif /* !_PTHREAD_PRIVATE_H */ diff --git a/lib/libc_r/uthread/uthread_accept.c b/lib/libc_r/uthread/uthread_accept.c new file mode 100644 index 0000000..e04b97b --- /dev/null +++ b/lib/libc_r/uthread/uthread_accept.c @@ -0,0 +1,110 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <fcntl.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_accept, accept); + +int +_accept(int fd, struct sockaddr * name, socklen_t *namelen) +{ + struct pthread *curthread = _get_curthread(); + int ret; + + /* Lock the file descriptor: */ + if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) { + /* Enter a loop to wait for a connection request: */ + while ((ret = __sys_accept(fd, name, namelen)) < 0) { + /* Check if the socket is to block: */ + if ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0 && (errno == EWOULDBLOCK || errno == EAGAIN)) { + /* Save the socket file descriptor: */ + curthread->data.fd.fd = fd; + curthread->data.fd.fname = __FILE__; + curthread->data.fd.branch = __LINE__; + + /* Set the timeout: */ + _thread_kern_set_timeout(NULL); + curthread->interrupted = 0; + + /* Schedule the next thread: */ + _thread_kern_sched_state(PS_FDR_WAIT, __FILE__, __LINE__); + + /* Check if the wait was interrupted: */ + if (curthread->interrupted) { + /* Return an error status: */ + errno = EINTR; + ret = -1; + break; + } + } else { + /* + * Another error has occurred, so exit the + * loop here: + */ + break; + } + } + + /* Check for errors: */ + if (ret < 0) { + } + /* Initialise the file descriptor table for the new socket: */ + else if (_thread_fd_table_init(ret) != 0) { + /* Quietly close the socket: */ + __sys_close(ret); + + /* Return an error: */ + ret = -1; + } + /* + * If the parent socket was blocking, make sure that + * the new socket is also set blocking here (as the + * call to _thread_fd_table_init() above will always + * set the new socket flags to non-blocking, as that + * will be the inherited state of the new socket. + */ + if((ret > 0) && (_thread_fd_table[fd]->flags & O_NONBLOCK) == 0) + _thread_fd_table[ret]->flags &= ~O_NONBLOCK; + + /* Unlock the file descriptor: */ + _FD_UNLOCK(fd, FD_RDWR); + } + /* Return the socket file descriptor or -1 on error: */ + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_acl_aclcheck_fd.c b/lib/libc_r/uthread/uthread_acl_aclcheck_fd.c new file mode 100644 index 0000000..19e9aaa --- /dev/null +++ b/lib/libc_r/uthread/uthread_acl_aclcheck_fd.c @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 2001 Thomas Moestl + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include <sys/types.h> +#include <sys/acl.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(___acl_aclcheck_fd, __acl_aclcheck_fd); + +int +___acl_aclcheck_fd(int fd, acl_type_t tp, acl_t acl) +{ + int error; + + if ((error = _FD_LOCK(fd, FD_READ, NULL)) == 0) { + error = __sys___acl_aclcheck_fd(fd, tp, (struct acl *)acl); + _FD_UNLOCK(fd, FD_READ); + } + return (error); +} + diff --git a/lib/libc_r/uthread/uthread_acl_delete_fd.c b/lib/libc_r/uthread/uthread_acl_delete_fd.c new file mode 100644 index 0000000..2368c5f --- /dev/null +++ b/lib/libc_r/uthread/uthread_acl_delete_fd.c @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 2001 Thomas Moestl + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include <sys/types.h> +#include <sys/acl.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(___acl_delete_fd, __acl_delete_fd); + +int +___acl_delete_fd(int fd, acl_type_t tp) +{ + int error; + + if ((error = _FD_LOCK(fd, FD_WRITE, NULL)) == 0) { + error = __sys___acl_delete_fd(fd, tp); + _FD_UNLOCK(fd, FD_WRITE); + } + return (error); +} diff --git a/lib/libc_r/uthread/uthread_acl_get_fd.c b/lib/libc_r/uthread/uthread_acl_get_fd.c new file mode 100644 index 0000000..f0fa8b1 --- /dev/null +++ b/lib/libc_r/uthread/uthread_acl_get_fd.c @@ -0,0 +1,47 @@ +/*- + * Copyright (c) 2001 Thomas Moestl + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include <sys/types.h> +#include <sys/acl.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(___acl_get_fd, __acl_get_fd); + +int +___acl_get_fd(int fd, acl_type_t tp, struct acl *acl_p) +{ + int error; + + if ((error = _FD_LOCK(fd, FD_READ, NULL)) == 0) { + error = __sys___acl_get_fd(fd, tp, acl_p); + _FD_UNLOCK(fd, FD_READ); + } + return (error); + +} diff --git a/lib/libc_r/uthread/uthread_acl_set_fd.c b/lib/libc_r/uthread/uthread_acl_set_fd.c new file mode 100644 index 0000000..c68751a --- /dev/null +++ b/lib/libc_r/uthread/uthread_acl_set_fd.c @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 2001 Thomas Moestl + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include <sys/types.h> +#include <sys/acl.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(___acl_set_fd, __acl_set_fd); + +int +___acl_set_fd(int fd, acl_type_t tp, struct acl *acl_p) +{ + int error; + + if ((error = _FD_LOCK(fd, FD_WRITE, NULL)) == 0) { + error = __sys___acl_set_fd(fd, tp, acl_p); + _FD_UNLOCK(fd, FD_WRITE); + } + return (error); +} diff --git a/lib/libc_r/uthread/uthread_aio_suspend.c b/lib/libc_r/uthread/uthread_aio_suspend.c new file mode 100644 index 0000000..23d34f9 --- /dev/null +++ b/lib/libc_r/uthread/uthread_aio_suspend.c @@ -0,0 +1,50 @@ +/* + * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. + * 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(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) 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. + * + * $FreeBSD$ + */ + +#include <aio.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_aio_suspend, aio_suspend); + +int +_aio_suspend(const struct aiocb * const iocbs[], int niocb, const struct + timespec *timeout) +{ + int ret; + + _thread_enter_cancellation_point(); + ret = __sys_aio_suspend(iocbs, niocb, timeout); + _thread_leave_cancellation_point(); + + return ret; +} + diff --git a/lib/libc_r/uthread/uthread_attr_destroy.c b/lib/libc_r/uthread/uthread_attr_destroy.c new file mode 100644 index 0000000..420bd5a --- /dev/null +++ b/lib/libc_r/uthread/uthread_attr_destroy.c @@ -0,0 +1,62 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <stdlib.h> +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_attr_destroy, pthread_attr_destroy); + +int +_pthread_attr_destroy(pthread_attr_t *attr) +{ + int ret; + + /* Check for invalid arguments: */ + if (attr == NULL || *attr == NULL) + /* Invalid argument: */ + ret = EINVAL; + else { + /* Free the memory allocated to the attribute object: */ + free(*attr); + + /* + * Leave the attribute pointer NULL now that the memory + * has been freed: + */ + *attr = NULL; + ret = 0; + } + return(ret); +} diff --git a/lib/libc_r/uthread/uthread_attr_getdetachstate.c b/lib/libc_r/uthread/uthread_attr_getdetachstate.c new file mode 100644 index 0000000..515248d --- /dev/null +++ b/lib/libc_r/uthread/uthread_attr_getdetachstate.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 1997 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_attr_getdetachstate, pthread_attr_getdetachstate); + +int +_pthread_attr_getdetachstate(const pthread_attr_t *attr, int *detachstate) +{ + int ret; + + /* Check for invalid arguments: */ + if (attr == NULL || *attr == NULL || detachstate == NULL) + ret = EINVAL; + else { + /* Check if the detached flag is set: */ + if ((*attr)->flags & PTHREAD_DETACHED) + /* Return detached: */ + *detachstate = PTHREAD_CREATE_DETACHED; + else + /* Return joinable: */ + *detachstate = PTHREAD_CREATE_JOINABLE; + ret = 0; + } + return(ret); +} diff --git a/lib/libc_r/uthread/uthread_attr_getguardsize.c b/lib/libc_r/uthread/uthread_attr_getguardsize.c new file mode 100644 index 0000000..849bf27 --- /dev/null +++ b/lib/libc_r/uthread/uthread_attr_getguardsize.c @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2001 Jason Evans <jasone@freebsd.org>. + * 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(s), this list of conditions and the following disclaimer + * unmodified other than the allowable addition of one or more + * copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) 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. + * + * $FreeBSD$ + */ + +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_attr_getguardsize, pthread_attr_getguardsize); + +int +_pthread_attr_getguardsize(const pthread_attr_t *attr, size_t *guardsize) +{ + int ret; + + /* Check for invalid arguments: */ + if (attr == NULL || *attr == NULL || guardsize == NULL) + ret = EINVAL; + else { + /* Return the guard size: */ + *guardsize = (*attr)->guardsize_attr; + ret = 0; + } + return(ret); +} diff --git a/lib/libc_r/uthread/uthread_attr_getinheritsched.c b/lib/libc_r/uthread/uthread_attr_getinheritsched.c new file mode 100644 index 0000000..6d6d324 --- /dev/null +++ b/lib/libc_r/uthread/uthread_attr_getinheritsched.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * 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 Daniel Eischen. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_attr_getinheritsched, pthread_attr_getinheritsched); + +int +_pthread_attr_getinheritsched(const pthread_attr_t *attr, int *sched_inherit) +{ + int ret = 0; + + if ((attr == NULL) || (*attr == NULL)) + ret = EINVAL; + else + *sched_inherit = (*attr)->sched_inherit; + + return(ret); +} diff --git a/lib/libc_r/uthread/uthread_attr_getschedparam.c b/lib/libc_r/uthread/uthread_attr_getschedparam.c new file mode 100644 index 0000000..cac86fa --- /dev/null +++ b/lib/libc_r/uthread/uthread_attr_getschedparam.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * 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 Daniel Eischen. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_attr_getschedparam, pthread_attr_getschedparam); + +int +_pthread_attr_getschedparam(const pthread_attr_t *attr, struct sched_param *param) +{ + int ret = 0; + + if ((attr == NULL) || (*attr == NULL) || (param == NULL)) + ret = EINVAL; + else + param->sched_priority = (*attr)->prio; + + return(ret); +} diff --git a/lib/libc_r/uthread/uthread_attr_getschedpolicy.c b/lib/libc_r/uthread/uthread_attr_getschedpolicy.c new file mode 100644 index 0000000..f2b74fc --- /dev/null +++ b/lib/libc_r/uthread/uthread_attr_getschedpolicy.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * 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 Daniel Eischen. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_attr_getschedpolicy, pthread_attr_getschedpolicy); + +int +_pthread_attr_getschedpolicy(const pthread_attr_t *attr, int *policy) +{ + int ret = 0; + + if ((attr == NULL) || (*attr == NULL) || (policy == NULL)) + ret = EINVAL; + else + *policy = (*attr)->sched_policy; + + return(ret); +} diff --git a/lib/libc_r/uthread/uthread_attr_getscope.c b/lib/libc_r/uthread/uthread_attr_getscope.c new file mode 100644 index 0000000..8abf418 --- /dev/null +++ b/lib/libc_r/uthread/uthread_attr_getscope.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * 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 Daniel Eischen. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_attr_getscope, pthread_attr_getscope); + +int +_pthread_attr_getscope(const pthread_attr_t *attr, int *contentionscope) +{ + int ret = 0; + + if ((attr == NULL) || (*attr == NULL) || (contentionscope == NULL)) + /* Return an invalid argument: */ + ret = EINVAL; + + else + *contentionscope = (*attr)->flags & PTHREAD_SCOPE_SYSTEM ? + PTHREAD_SCOPE_SYSTEM : PTHREAD_SCOPE_PROCESS; + + return(ret); +} diff --git a/lib/libc_r/uthread/uthread_attr_getstackaddr.c b/lib/libc_r/uthread/uthread_attr_getstackaddr.c new file mode 100644 index 0000000..0cef0f3 --- /dev/null +++ b/lib/libc_r/uthread/uthread_attr_getstackaddr.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1997 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_attr_getstackaddr, pthread_attr_getstackaddr); + +int +_pthread_attr_getstackaddr(const pthread_attr_t *attr, void **stackaddr) +{ + int ret; + + /* Check for invalid arguments: */ + if (attr == NULL || *attr == NULL || stackaddr == NULL) + ret = EINVAL; + else { + /* Return the stack address: */ + *stackaddr = (*attr)->stackaddr_attr; + ret = 0; + } + return(ret); +} diff --git a/lib/libc_r/uthread/uthread_attr_getstacksize.c b/lib/libc_r/uthread/uthread_attr_getstacksize.c new file mode 100644 index 0000000..091a0c7 --- /dev/null +++ b/lib/libc_r/uthread/uthread_attr_getstacksize.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1997 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_attr_getstacksize, pthread_attr_getstacksize); + +int +_pthread_attr_getstacksize(const pthread_attr_t *attr, size_t *stacksize) +{ + int ret; + + /* Check for invalid arguments: */ + if (attr == NULL || *attr == NULL || stacksize == NULL) + ret = EINVAL; + else { + /* Return the stack size: */ + *stacksize = (*attr)->stacksize_attr; + ret = 0; + } + return(ret); +} diff --git a/lib/libc_r/uthread/uthread_attr_init.c b/lib/libc_r/uthread/uthread_attr_init.c new file mode 100644 index 0000000..e10d521 --- /dev/null +++ b/lib/libc_r/uthread/uthread_attr_init.c @@ -0,0 +1,61 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_attr_init, pthread_attr_init); + +int +_pthread_attr_init(pthread_attr_t *attr) +{ + int ret; + pthread_attr_t pattr; + + /* Allocate memory for the attribute object: */ + if ((pattr = (pthread_attr_t) malloc(sizeof(struct pthread_attr))) == NULL) + /* Insufficient memory: */ + ret = ENOMEM; + else { + /* Initialise the attribute object with the defaults: */ + memcpy(pattr, &pthread_attr_default, sizeof(struct pthread_attr)); + + /* Return a pointer to the attribute object: */ + *attr = pattr; + ret = 0; + } + return(ret); +} diff --git a/lib/libc_r/uthread/uthread_attr_setcreatesuspend_np.c b/lib/libc_r/uthread/uthread_attr_setcreatesuspend_np.c new file mode 100644 index 0000000..be6f8d7 --- /dev/null +++ b/lib/libc_r/uthread/uthread_attr_setcreatesuspend_np.c @@ -0,0 +1,52 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_attr_setcreatesuspend_np, pthread_attr_setcreatesuspend_np); + +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); +} diff --git a/lib/libc_r/uthread/uthread_attr_setdetachstate.c b/lib/libc_r/uthread/uthread_attr_setdetachstate.c new file mode 100644 index 0000000..e0e23c2 --- /dev/null +++ b/lib/libc_r/uthread/uthread_attr_setdetachstate.c @@ -0,0 +1,61 @@ +/* + * Copyright (c) 1997 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_attr_setdetachstate, pthread_attr_setdetachstate); + +int +_pthread_attr_setdetachstate(pthread_attr_t *attr, int detachstate) +{ + int ret; + + /* Check for invalid arguments: */ + if (attr == NULL || *attr == NULL || + (detachstate != PTHREAD_CREATE_DETACHED && + detachstate != PTHREAD_CREATE_JOINABLE)) + ret = EINVAL; + else { + /* Check if detached state: */ + if (detachstate == PTHREAD_CREATE_DETACHED) + /* Set the detached flag: */ + (*attr)->flags |= PTHREAD_DETACHED; + else + /* Reset the detached flag: */ + (*attr)->flags &= ~PTHREAD_DETACHED; + ret = 0; + } + return(ret); +} diff --git a/lib/libc_r/uthread/uthread_attr_setguardsize.c b/lib/libc_r/uthread/uthread_attr_setguardsize.c new file mode 100644 index 0000000..0c3de14 --- /dev/null +++ b/lib/libc_r/uthread/uthread_attr_setguardsize.c @@ -0,0 +1,57 @@ +/* + * Copyright (C) 2001 Jason Evans <jasone@freebsd.org>. + * 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(s), this list of conditions and the following disclaimer + * unmodified other than the allowable addition of one or more + * copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) 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. + * + * $FreeBSD$ + */ + +#include <sys/param.h> +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_attr_setguardsize, pthread_attr_setguardsize); + +int +_pthread_attr_setguardsize(pthread_attr_t *attr, size_t guardsize) +{ + int ret; + + /* Check for invalid arguments. */ + if (attr == NULL || *attr == NULL) + ret = EINVAL; + else { + /* Round guardsize up to the nearest multiple of PAGE_SIZE. */ + if (guardsize % PAGE_SIZE != 0) + guardsize = ((guardsize / PAGE_SIZE) + 1) * PAGE_SIZE; + + /* Save the stack size. */ + (*attr)->guardsize_attr = guardsize; + ret = 0; + } + return(ret); +} diff --git a/lib/libc_r/uthread/uthread_attr_setinheritsched.c b/lib/libc_r/uthread/uthread_attr_setinheritsched.c new file mode 100644 index 0000000..3538131 --- /dev/null +++ b/lib/libc_r/uthread/uthread_attr_setinheritsched.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * 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 Daniel Eischen. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_attr_setinheritsched, pthread_attr_setinheritsched); + +int +_pthread_attr_setinheritsched(pthread_attr_t *attr, int sched_inherit) +{ + int ret = 0; + + if ((attr == NULL) || (*attr == NULL)) + ret = EINVAL; + else + (*attr)->sched_inherit = sched_inherit; + + return(ret); +} diff --git a/lib/libc_r/uthread/uthread_attr_setschedparam.c b/lib/libc_r/uthread/uthread_attr_setschedparam.c new file mode 100644 index 0000000..c42973e --- /dev/null +++ b/lib/libc_r/uthread/uthread_attr_setschedparam.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * 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 Daniel Eischen. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_attr_setschedparam, pthread_attr_setschedparam); + +int +_pthread_attr_setschedparam(pthread_attr_t *attr, const struct sched_param *param) +{ + int ret = 0; + + if ((attr == NULL) || (*attr == NULL)) + ret = EINVAL; + else if (param == NULL) { + ret = ENOTSUP; + } else if ((param->sched_priority < PTHREAD_MIN_PRIORITY) || + (param->sched_priority > PTHREAD_MAX_PRIORITY)) { + /* Return an unsupported value error. */ + ret = ENOTSUP; + } else + (*attr)->prio = param->sched_priority; + + return(ret); +} diff --git a/lib/libc_r/uthread/uthread_attr_setschedpolicy.c b/lib/libc_r/uthread/uthread_attr_setschedpolicy.c new file mode 100644 index 0000000..d9c83e6 --- /dev/null +++ b/lib/libc_r/uthread/uthread_attr_setschedpolicy.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * 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 Daniel Eischen. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_attr_setschedpolicy, pthread_attr_setschedpolicy); + +int +_pthread_attr_setschedpolicy(pthread_attr_t *attr, int policy) +{ + int ret = 0; + + if ((attr == NULL) || (*attr == NULL)) + ret = EINVAL; + else if ((policy < SCHED_FIFO) || (policy > SCHED_RR)) { + ret = ENOTSUP; + } else + (*attr)->sched_policy = policy; + + return(ret); +} diff --git a/lib/libc_r/uthread/uthread_attr_setscope.c b/lib/libc_r/uthread/uthread_attr_setscope.c new file mode 100644 index 0000000..3614615 --- /dev/null +++ b/lib/libc_r/uthread/uthread_attr_setscope.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * 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 Daniel Eischen. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_attr_setscope, pthread_attr_setscope); + +int +_pthread_attr_setscope(pthread_attr_t *attr, int contentionscope) +{ + int ret = 0; + + if ((attr == NULL) || (*attr == NULL)) { + /* Return an invalid argument: */ + ret = EINVAL; + } else if ((contentionscope != PTHREAD_SCOPE_PROCESS) || + (contentionscope == PTHREAD_SCOPE_SYSTEM)) { + /* We don't support PTHREAD_SCOPE_SYSTEM. */ + ret = ENOTSUP; + } else + (*attr)->flags |= contentionscope; + + return(ret); +} diff --git a/lib/libc_r/uthread/uthread_attr_setstackaddr.c b/lib/libc_r/uthread/uthread_attr_setstackaddr.c new file mode 100644 index 0000000..6046932 --- /dev/null +++ b/lib/libc_r/uthread/uthread_attr_setstackaddr.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1997 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_attr_setstackaddr, pthread_attr_setstackaddr); + +int +_pthread_attr_setstackaddr(pthread_attr_t *attr, void *stackaddr) +{ + int ret; + + /* Check for invalid arguments: */ + if (attr == NULL || *attr == NULL || stackaddr == NULL) + ret = EINVAL; + else { + /* Save the stack address: */ + (*attr)->stackaddr_attr = stackaddr; + ret = 0; + } + return(ret); +} diff --git a/lib/libc_r/uthread/uthread_attr_setstacksize.c b/lib/libc_r/uthread/uthread_attr_setstacksize.c new file mode 100644 index 0000000..622ba7f --- /dev/null +++ b/lib/libc_r/uthread/uthread_attr_setstacksize.c @@ -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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_attr_setstacksize, pthread_attr_setstacksize); + +int +_pthread_attr_setstacksize(pthread_attr_t *attr, size_t stacksize) +{ + int ret; + + /* Check for invalid arguments: */ + if (attr == NULL || *attr == NULL || stacksize < PTHREAD_STACK_MIN) + ret = EINVAL; + else { + /* Save the stack size: */ + (*attr)->stacksize_attr = stacksize; + ret = 0; + } + return(ret); +} diff --git a/lib/libc_r/uthread/uthread_autoinit.cc b/lib/libc_r/uthread/uthread_autoinit.cc new file mode 100644 index 0000000..b04caff --- /dev/null +++ b/lib/libc_r/uthread/uthread_autoinit.cc @@ -0,0 +1,89 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +/* + * This module uses the magic of C++ static constructors to initialize the + * threads package at program start-up time. + * + * Note: Because of a bug in certain versions of "/usr/lib/c++rt0.o", you + * should _not_ enclose the body of this module in an "#ifdef _THREAD_SAFE" + * conditional. + */ + +extern "C" void _thread_init(void); + +/* + * First, we declare a class with a constructor. + */ +class _thread_init_invoker { +public: + _thread_init_invoker(); /* Constructor declaration. */ +}; + +/* + * Here is the definition of the constructor. All it does is call the + * threads initialization function, "_thread_init". + */ +_thread_init_invoker::_thread_init_invoker() +{ + _thread_init(); +} + +/* + * Here is a single, static instance of our "_thread_init_invoker" class. + * The mere existance of this instance will result in its constructor + * being called, automatically, at program start-up time. + */ +static _thread_init_invoker the_thread_init_invoker; + +/* + * For the shared version of the threads library, the above is sufficient. + * But for the archive version of the library, we need a little bit more. + * Namely, we must arrange for this particular module to be pulled in from + * the archive library at link time. To accomplish that, we define and + * initialize a variable, "_thread_autoinit_dummy_decl". This variable is + * referenced (as an extern) from libc/stdlib/exit.c. This will always + * create a need for this module, ensuring that it is present in the + * executable. + * + * We know that, if the user does _anything_ at all with threads, then the + * "uthread_init.c" module will be linked in. That is the case because + * "uthread_init.c" is the module that defines all of the global variables + * used by the threads library. The presence of "uthread_init.c" will, in + * turn, force this module to be linked in. And the presence of this module + * in the executable will result in the constructor being invoked, and + * "_thread_init" being called. + */ +extern "C" int _thread_autoinit_dummy_decl; /* Declare with "C" linkage */ +int _thread_autoinit_dummy_decl = 0; diff --git a/lib/libc_r/uthread/uthread_bind.c b/lib/libc_r/uthread/uthread_bind.c new file mode 100644 index 0000000..bb076b0 --- /dev/null +++ b/lib/libc_r/uthread/uthread_bind.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <sys/types.h> +#include <sys/socket.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_bind, bind); + +int +_bind(int fd, const struct sockaddr * name, socklen_t namelen) +{ + int ret; + + if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) { + ret = __sys_bind(fd, name, namelen); + _FD_UNLOCK(fd, FD_RDWR); + } + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_cancel.c b/lib/libc_r/uthread/uthread_cancel.c new file mode 100644 index 0000000..cf72d89 --- /dev/null +++ b/lib/libc_r/uthread/uthread_cancel.c @@ -0,0 +1,243 @@ +/* + * David Leonard <d@openbsd.org>, 1999. Public domain. + * $FreeBSD$ + */ +#include <sys/errno.h> +#include <pthread.h> +#include "pthread_private.h" + +static void finish_cancellation(void *arg); + +__weak_reference(_pthread_cancel, pthread_cancel); +__weak_reference(_pthread_setcancelstate, pthread_setcancelstate); +__weak_reference(_pthread_setcanceltype, pthread_setcanceltype); +__weak_reference(_pthread_testcancel, pthread_testcancel); + +int +_pthread_cancel(pthread_t pthread) +{ + int ret; + + if ((ret = _find_thread(pthread)) != 0) { + /* NOTHING */ + } else if (pthread->state == PS_DEAD || pthread->state == PS_DEADLOCK) { + ret = 0; + } else { + /* Protect the scheduling queues: */ + _thread_kern_sig_defer(); + + if (((pthread->cancelflags & PTHREAD_CANCEL_DISABLE) != 0) || + (((pthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) == 0) && + ((pthread->cancelflags & PTHREAD_AT_CANCEL_POINT) == 0))) + /* Just mark it for cancellation: */ + pthread->cancelflags |= PTHREAD_CANCELLING; + else { + /* + * Check if we need to kick it back into the + * run queue: + */ + switch (pthread->state) { + case PS_RUNNING: + /* No need to resume: */ + pthread->cancelflags |= PTHREAD_CANCELLING; + break; + + case PS_SPINBLOCK: + case PS_FDR_WAIT: + case PS_FDW_WAIT: + case PS_POLL_WAIT: + case PS_SELECT_WAIT: + /* Remove these threads from the work queue: */ + if ((pthread->flags & PTHREAD_FLAGS_IN_WORKQ) + != 0) + PTHREAD_WORKQ_REMOVE(pthread); + /* Fall through: */ + case PS_SIGTHREAD: + case PS_SLEEP_WAIT: + case PS_WAIT_WAIT: + case PS_SIGSUSPEND: + case PS_SIGWAIT: + /* Interrupt and resume: */ + pthread->interrupted = 1; + pthread->cancelflags |= PTHREAD_CANCELLING; + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + break; + + case PS_JOIN: + /* + * Disconnect the thread from the joinee: + */ + if (pthread->join_status.thread != NULL) { + pthread->join_status.thread->joiner + = NULL; + pthread->join_status.thread = NULL; + } + pthread->cancelflags |= PTHREAD_CANCELLING; + PTHREAD_NEW_STATE(pthread, PS_RUNNING); + break; + + case PS_SUSPENDED: + if (pthread->suspended == SUSP_NO || + pthread->suspended == SUSP_YES || + pthread->suspended == SUSP_JOIN || + pthread->suspended == SUSP_NOWAIT) { + /* + * This thread isn't in any scheduling + * queues; just change it's state: + */ + pthread->cancelflags |= + PTHREAD_CANCELLING; + PTHREAD_SET_STATE(pthread, PS_RUNNING); + break; + } + /* FALLTHROUGH */ + case PS_MUTEX_WAIT: + case PS_COND_WAIT: + case PS_FDLR_WAIT: + case PS_FDLW_WAIT: + case PS_FILE_WAIT: + /* + * Threads in these states may be in queues. + * In order to preserve queue integrity, the + * cancelled thread must remove itself from the + * queue. Mark the thread as interrupted and + * needing cancellation, and set the state to + * running. When the thread resumes, it will + * remove itself from the queue and call the + * cancellation completion routine. + */ + pthread->interrupted = 1; + pthread->cancelflags |= PTHREAD_CANCEL_NEEDED; + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + pthread->continuation = finish_cancellation; + break; + + case PS_DEAD: + case PS_DEADLOCK: + case PS_STATE_MAX: + /* Ignore - only here to silence -Wall: */ + break; + } + } + + /* Unprotect the scheduling queues: */ + _thread_kern_sig_undefer(); + + ret = 0; + } + return (ret); +} + +int +_pthread_setcancelstate(int state, int *oldstate) +{ + struct pthread *curthread = _get_curthread(); + int ostate; + int ret; + + ostate = curthread->cancelflags & PTHREAD_CANCEL_DISABLE; + + switch (state) { + case PTHREAD_CANCEL_ENABLE: + if (oldstate != NULL) + *oldstate = ostate; + curthread->cancelflags &= ~PTHREAD_CANCEL_DISABLE; + if ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0) + pthread_testcancel(); + ret = 0; + break; + case PTHREAD_CANCEL_DISABLE: + if (oldstate != NULL) + *oldstate = ostate; + curthread->cancelflags |= PTHREAD_CANCEL_DISABLE; + ret = 0; + break; + default: + ret = EINVAL; + } + + return (ret); +} + +int +_pthread_setcanceltype(int type, int *oldtype) +{ + struct pthread *curthread = _get_curthread(); + int otype; + int ret; + + otype = curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS; + switch (type) { + case PTHREAD_CANCEL_ASYNCHRONOUS: + if (oldtype != NULL) + *oldtype = otype; + curthread->cancelflags |= PTHREAD_CANCEL_ASYNCHRONOUS; + pthread_testcancel(); + ret = 0; + break; + case PTHREAD_CANCEL_DEFERRED: + if (oldtype != NULL) + *oldtype = otype; + curthread->cancelflags &= ~PTHREAD_CANCEL_ASYNCHRONOUS; + ret = 0; + break; + default: + ret = EINVAL; + } + + return (ret); +} + +void +_pthread_testcancel(void) +{ + struct pthread *curthread = _get_curthread(); + + if (((curthread->cancelflags & PTHREAD_CANCEL_DISABLE) == 0) && + ((curthread->cancelflags & PTHREAD_CANCELLING) != 0)) { + /* + * It is possible for this thread to be swapped out + * while performing cancellation; do not allow it + * to be cancelled again. + */ + curthread->cancelflags &= ~PTHREAD_CANCELLING; + _thread_exit_cleanup(); + pthread_exit(PTHREAD_CANCELED); + PANIC("cancel"); + } +} + +void +_thread_enter_cancellation_point(void) +{ + struct pthread *curthread = _get_curthread(); + + /* Look for a cancellation before we block: */ + pthread_testcancel(); + curthread->cancelflags |= PTHREAD_AT_CANCEL_POINT; +} + +void +_thread_leave_cancellation_point(void) +{ + struct pthread *curthread = _get_curthread(); + + curthread->cancelflags &= ~PTHREAD_AT_CANCEL_POINT; + /* Look for a cancellation after we unblock: */ + pthread_testcancel(); +} + +static void +finish_cancellation(void *arg) +{ + struct pthread *curthread = _get_curthread(); + + curthread->continuation = NULL; + curthread->interrupted = 0; + + if ((curthread->cancelflags & PTHREAD_CANCEL_NEEDED) != 0) { + curthread->cancelflags &= ~PTHREAD_CANCEL_NEEDED; + _thread_exit_cleanup(); + pthread_exit(PTHREAD_CANCELED); + } +} diff --git a/lib/libc_r/uthread/uthread_cap_get_fd.c b/lib/libc_r/uthread/uthread_cap_get_fd.c new file mode 100644 index 0000000..7d42917 --- /dev/null +++ b/lib/libc_r/uthread/uthread_cap_get_fd.c @@ -0,0 +1,48 @@ +/*- + * Copyright (c) 2001 Thomas Moestl + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include <sys/types.h> +#include <sys/capability.h> +#include <pthread.h> +#include "pthread_private.h" + +#pragma weak __cap_get_fd=___cap_get_fd + +int +___cap_get_fd(int fd, struct cap *cap_p) +{ + int error; + + if ((error = _FD_LOCK(fd, FD_READ, NULL)) == 0) { + error = __sys___cap_get_fd(fd, cap_p); + _FD_UNLOCK(fd, FD_READ); + } + return (error); +} + + diff --git a/lib/libc_r/uthread/uthread_cap_set_fd.c b/lib/libc_r/uthread/uthread_cap_set_fd.c new file mode 100644 index 0000000..e911b6b --- /dev/null +++ b/lib/libc_r/uthread/uthread_cap_set_fd.c @@ -0,0 +1,46 @@ +/*- + * Copyright (c) 2001 Thomas Moestl + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include <sys/types.h> +#include <sys/capability.h> +#include <pthread.h> +#include "pthread_private.h" + +#pragma weak __cap_set_fd=___cap_set_fd + +int +___cap_set_fd(int fd, cap_t cap_p) +{ + int error; + + if ((error = _FD_LOCK(fd, FD_WRITE, NULL)) == 0) { + error = __sys___cap_set_fd(fd, cap_p); + _FD_UNLOCK(fd, FD_WRITE); + } + return (error); +} diff --git a/lib/libc_r/uthread/uthread_clean.c b/lib/libc_r/uthread/uthread_clean.c new file mode 100644 index 0000000..6330cb9 --- /dev/null +++ b/lib/libc_r/uthread/uthread_clean.c @@ -0,0 +1,72 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <signal.h> +#include <errno.h> +#include <stdlib.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_cleanup_push, pthread_cleanup_push); +__weak_reference(_pthread_cleanup_pop, pthread_cleanup_pop); + +void +_pthread_cleanup_push(void (*routine) (void *), void *routine_arg) +{ + struct pthread *curthread = _get_curthread(); + struct pthread_cleanup *new; + + if ((new = (struct pthread_cleanup *) malloc(sizeof(struct pthread_cleanup))) != NULL) { + new->routine = routine; + new->routine_arg = routine_arg; + new->next = curthread->cleanup; + + curthread->cleanup = new; + } +} + +void +_pthread_cleanup_pop(int execute) +{ + struct pthread *curthread = _get_curthread(); + struct pthread_cleanup *old; + + if ((old = curthread->cleanup) != NULL) { + curthread->cleanup = old->next; + if (execute) { + old->routine(old->routine_arg); + } + free(old); + } +} + diff --git a/lib/libc_r/uthread/uthread_close.c b/lib/libc_r/uthread/uthread_close.c new file mode 100644 index 0000000..0a5bd24 --- /dev/null +++ b/lib/libc_r/uthread/uthread_close.c @@ -0,0 +1,114 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(__close, close); + +int +_close(int fd) +{ + int flags; + int ret; + struct stat sb; + struct fd_table_entry *entry; + + if ((fd == _thread_kern_pipe[0]) || (fd == _thread_kern_pipe[1])) { + /* + * Don't allow silly programs to close the kernel pipe. + */ + errno = EBADF; + ret = -1; + } + /* + * Lock the file descriptor while the file is closed and get + * the file descriptor status: + */ + else if (((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) && + ((ret = __sys_fstat(fd, &sb)) == 0)) { + /* + * 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 = __sys_fcntl(fd, F_GETFL, NULL); + /* Clear the nonblocking file descriptor flag: */ + __sys_fcntl(fd, F_SETFL, flags & ~O_NONBLOCK); + } + + /* XXX: Assumes well behaved threads. */ + /* XXX: Defer real close to avoid race condition */ + entry = _thread_fd_table[fd]; + _thread_fd_table[fd] = NULL; + free(entry); + + /* Close the file descriptor: */ + ret = __sys_close(fd); + } + return (ret); +} + +int +__close(int fd) +{ + int ret; + + _thread_enter_cancellation_point(); + ret = _close(fd); + _thread_leave_cancellation_point(); + + return ret; +} diff --git a/lib/libc_r/uthread/uthread_cond.c b/lib/libc_r/uthread/uthread_cond.c new file mode 100644 index 0000000..7f3fe7a --- /dev/null +++ b/lib/libc_r/uthread/uthread_cond.c @@ -0,0 +1,747 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <pthread.h> +#include "pthread_private.h" + +/* + * Prototypes + */ +static inline pthread_t cond_queue_deq(pthread_cond_t); +static inline void cond_queue_remove(pthread_cond_t, pthread_t); +static inline void cond_queue_enq(pthread_cond_t, pthread_t); + +__weak_reference(_pthread_cond_init, pthread_cond_init); +__weak_reference(_pthread_cond_destroy, pthread_cond_destroy); +__weak_reference(_pthread_cond_wait, pthread_cond_wait); +__weak_reference(_pthread_cond_timedwait, pthread_cond_timedwait); +__weak_reference(_pthread_cond_signal, pthread_cond_signal); +__weak_reference(_pthread_cond_broadcast, pthread_cond_broadcast); + + +/* Reinitialize a condition variable to defaults. */ +int +_cond_reinit(pthread_cond_t *cond) +{ + int ret = 0; + + if (cond == NULL) + ret = EINVAL; + else if (*cond == NULL) + ret = pthread_cond_init(cond, NULL); + else { + /* + * Initialize the condition variable structure: + */ + TAILQ_INIT(&(*cond)->c_queue); + (*cond)->c_flags = COND_FLAGS_INITED; + (*cond)->c_type = COND_TYPE_FAST; + (*cond)->c_mutex = NULL; + (*cond)->c_seqno = 0; + memset(&(*cond)->lock, 0, sizeof((*cond)->lock)); + } + return (ret); +} + +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; + + if (cond == NULL) + rval = EINVAL; + 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; + } + + /* 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: */ + rval = EINVAL; + break; + } + + /* Check for no errors: */ + if (rval == 0) { + if ((pcond = (pthread_cond_t) + malloc(sizeof(struct pthread_cond))) == NULL) { + rval = ENOMEM; + } else { + /* + * Initialise the condition variable + * structure: + */ + TAILQ_INIT(&pcond->c_queue); + pcond->c_flags |= COND_FLAGS_INITED; + pcond->c_type = type; + pcond->c_mutex = NULL; + pcond->c_seqno = 0; + memset(&pcond->lock,0,sizeof(pcond->lock)); + *cond = pcond; + } + } + } + /* Return the completion status: */ + return (rval); +} + +int +_pthread_cond_destroy(pthread_cond_t *cond) +{ + int rval = 0; + + if (cond == NULL || *cond == NULL) + rval = EINVAL; + else { + /* Lock the condition variable structure: */ + _SPINLOCK(&(*cond)->lock); + + /* + * Free the memory allocated for the condition + * variable structure: + */ + free(*cond); + + /* + * NULL the caller's pointer now that the condition + * variable has been destroyed: + */ + *cond = NULL; + } + /* Return the completion status: */ + return (rval); +} + +int +_pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) +{ + struct pthread *curthread = _get_curthread(); + int rval = 0; + int done = 0; + int interrupted = 0; + int seqno; + + _thread_enter_cancellation_point(); + + if (cond == NULL) + return (EINVAL); + + /* + * If the condition variable is statically initialized, + * perform the dynamic initialization: + */ + if (*cond == NULL && + (rval = pthread_cond_init(cond, NULL)) != 0) + return (rval); + + /* + * Enter a loop waiting for a condition signal or broadcast + * to wake up this thread. A loop is needed in case the waiting + * thread is interrupted by a signal to execute a signal handler. + * It is not (currently) possible to remain in the waiting queue + * while running a handler. Instead, the thread is interrupted + * and backed out of the waiting queue prior to executing the + * signal handler. + */ + do { + /* Lock the condition variable structure: */ + _SPINLOCK(&(*cond)->lock); + + /* + * If the condvar was statically allocated, properly + * initialize the tail queue. + */ + if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) { + TAILQ_INIT(&(*cond)->c_queue); + (*cond)->c_flags |= COND_FLAGS_INITED; + } + + /* Process according to condition variable type: */ + switch ((*cond)->c_type) { + /* Fast condition variable: */ + case COND_TYPE_FAST: + if ((mutex == NULL) || (((*cond)->c_mutex != NULL) && + ((*cond)->c_mutex != *mutex))) { + /* Unlock the condition variable structure: */ + _SPINUNLOCK(&(*cond)->lock); + + /* Return invalid argument error: */ + rval = EINVAL; + } else { + /* Reset the timeout and interrupted flags: */ + curthread->timeout = 0; + curthread->interrupted = 0; + + /* + * Queue the running thread for the condition + * variable: + */ + cond_queue_enq(*cond, curthread); + + /* Remember the mutex and sequence number: */ + (*cond)->c_mutex = *mutex; + seqno = (*cond)->c_seqno; + + /* Wait forever: */ + curthread->wakeup_time.tv_sec = -1; + + /* Unlock the mutex: */ + if ((rval = _mutex_cv_unlock(mutex)) != 0) { + /* + * Cannot unlock the mutex, so remove + * the running thread from the condition + * variable queue: + */ + cond_queue_remove(*cond, curthread); + + /* Check for no more waiters: */ + if (TAILQ_FIRST(&(*cond)->c_queue) == + NULL) + (*cond)->c_mutex = NULL; + + /* Unlock the condition variable structure: */ + _SPINUNLOCK(&(*cond)->lock); + } else { + /* + * Schedule the next thread and unlock + * the condition variable structure: + */ + _thread_kern_sched_state_unlock(PS_COND_WAIT, + &(*cond)->lock, __FILE__, __LINE__); + + done = (seqno != (*cond)->c_seqno); + + interrupted = curthread->interrupted; + + /* + * Check if the wait was interrupted + * (canceled) or needs to be resumed + * after handling a signal. + */ + if (interrupted != 0) { + /* + * Lock the mutex and ignore any + * errors. Note that even + * though this thread may have + * been canceled, POSIX requires + * that the mutex be reaquired + * prior to cancellation. + */ + (void)_mutex_cv_lock(mutex); + } else { + /* + * Lock the condition variable + * while removing the thread. + */ + _SPINLOCK(&(*cond)->lock); + + cond_queue_remove(*cond, + curthread); + + /* Check for no more waiters: */ + if (TAILQ_FIRST(&(*cond)->c_queue) == NULL) + (*cond)->c_mutex = NULL; + + _SPINUNLOCK(&(*cond)->lock); + + /* Lock the mutex: */ + rval = _mutex_cv_lock(mutex); + } + } + } + break; + + /* Trap invalid condition variable types: */ + default: + /* Unlock the condition variable structure: */ + _SPINUNLOCK(&(*cond)->lock); + + /* Return an invalid argument error: */ + rval = EINVAL; + break; + } + + if ((interrupted != 0) && (curthread->continuation != NULL)) + curthread->continuation((void *) curthread); + } while ((done == 0) && (rval == 0)); + + _thread_leave_cancellation_point(); + + /* Return the completion status: */ + return (rval); +} + +int +_pthread_cond_timedwait(pthread_cond_t * cond, pthread_mutex_t * mutex, + const struct timespec * abstime) +{ + struct pthread *curthread = _get_curthread(); + int rval = 0; + int done = 0; + int interrupted = 0; + int seqno; + + _thread_enter_cancellation_point(); + + if (abstime == NULL || abstime->tv_sec < 0 || abstime->tv_nsec < 0 || + abstime->tv_nsec >= 1000000000) + return (EINVAL); + /* + * If the condition variable is statically initialized, perform dynamic + * initialization. + */ + if (*cond == NULL && (rval = pthread_cond_init(cond, NULL)) != 0) + return (rval); + + /* + * Enter a loop waiting for a condition signal or broadcast + * to wake up this thread. A loop is needed in case the waiting + * thread is interrupted by a signal to execute a signal handler. + * It is not (currently) possible to remain in the waiting queue + * while running a handler. Instead, the thread is interrupted + * and backed out of the waiting queue prior to executing the + * signal handler. + */ + do { + /* Lock the condition variable structure: */ + _SPINLOCK(&(*cond)->lock); + + /* + * If the condvar was statically allocated, properly + * initialize the tail queue. + */ + if (((*cond)->c_flags & COND_FLAGS_INITED) == 0) { + TAILQ_INIT(&(*cond)->c_queue); + (*cond)->c_flags |= COND_FLAGS_INITED; + } + + /* Process according to condition variable type: */ + switch ((*cond)->c_type) { + /* Fast condition variable: */ + case COND_TYPE_FAST: + if ((mutex == NULL) || (((*cond)->c_mutex != NULL) && + ((*cond)->c_mutex != *mutex))) { + /* Return invalid argument error: */ + rval = EINVAL; + + /* Unlock the condition variable structure: */ + _SPINUNLOCK(&(*cond)->lock); + } else { + /* Set the wakeup time: */ + curthread->wakeup_time.tv_sec = + abstime->tv_sec; + curthread->wakeup_time.tv_nsec = + abstime->tv_nsec; + + /* Reset the timeout and interrupted flags: */ + curthread->timeout = 0; + curthread->interrupted = 0; + + /* + * Queue the running thread for the condition + * variable: + */ + cond_queue_enq(*cond, curthread); + + /* Remember the mutex and sequence number: */ + (*cond)->c_mutex = *mutex; + seqno = (*cond)->c_seqno; + + /* Unlock the mutex: */ + if ((rval = _mutex_cv_unlock(mutex)) != 0) { + /* + * Cannot unlock the mutex, so remove + * the running thread from the condition + * variable queue: + */ + cond_queue_remove(*cond, curthread); + + /* Check for no more waiters: */ + if (TAILQ_FIRST(&(*cond)->c_queue) == NULL) + (*cond)->c_mutex = NULL; + + /* Unlock the condition variable structure: */ + _SPINUNLOCK(&(*cond)->lock); + } else { + /* + * Schedule the next thread and unlock + * the condition variable structure: + */ + _thread_kern_sched_state_unlock(PS_COND_WAIT, + &(*cond)->lock, __FILE__, __LINE__); + + done = (seqno != (*cond)->c_seqno); + + interrupted = curthread->interrupted; + + /* + * Check if the wait was interrupted + * (canceled) or needs to be resumed + * after handling a signal. + */ + if (interrupted != 0) { + /* + * Lock the mutex and ignore any + * errors. Note that even + * though this thread may have + * been canceled, POSIX requires + * that the mutex be reaquired + * prior to cancellation. + */ + (void)_mutex_cv_lock(mutex); + } else { + /* + * Lock the condition variable + * while removing the thread. + */ + _SPINLOCK(&(*cond)->lock); + + cond_queue_remove(*cond, + curthread); + + /* Check for no more waiters: */ + if (TAILQ_FIRST(&(*cond)->c_queue) == NULL) + (*cond)->c_mutex = NULL; + + _SPINUNLOCK(&(*cond)->lock); + + /* Lock the mutex: */ + rval = _mutex_cv_lock(mutex); + + /* + * Return ETIMEDOUT if the wait + * timed out and there wasn't an + * error locking the mutex: + */ + if ((curthread->timeout != 0) + && rval == 0) + rval = ETIMEDOUT; + + } + } + } + break; + + /* Trap invalid condition variable types: */ + default: + /* Unlock the condition variable structure: */ + _SPINUNLOCK(&(*cond)->lock); + + /* Return an invalid argument error: */ + rval = EINVAL; + break; + } + + if ((interrupted != 0) && (curthread->continuation != NULL)) + curthread->continuation((void *) curthread); + } while ((done == 0) && (rval == 0)); + + _thread_leave_cancellation_point(); + + /* Return the completion status: */ + return (rval); +} + +int +_pthread_cond_signal(pthread_cond_t * cond) +{ + int rval = 0; + pthread_t pthread; + + if (cond == NULL) + rval = EINVAL; + /* + * If the condition variable is statically initialized, perform dynamic + * initialization. + */ + else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) { + /* + * Defer signals to protect the scheduling queues + * from access by the signal handler: + */ + _thread_kern_sig_defer(); + + /* Lock the condition variable structure: */ + _SPINLOCK(&(*cond)->lock); + + /* Process according to condition variable type: */ + switch ((*cond)->c_type) { + /* Fast condition variable: */ + case COND_TYPE_FAST: + /* Increment the sequence number: */ + (*cond)->c_seqno++; + + if ((pthread = cond_queue_deq(*cond)) != NULL) { + /* + * Unless the thread is currently suspended, + * allow it to run. If the thread is suspended, + * make a note that the thread isn't in a wait + * queue any more. + */ + if (pthread->state != PS_SUSPENDED) + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + else + pthread->suspended = SUSP_NOWAIT; + } + + /* Check for no more waiters: */ + if (TAILQ_FIRST(&(*cond)->c_queue) == NULL) + (*cond)->c_mutex = NULL; + break; + + /* Trap invalid condition variable types: */ + default: + /* Return an invalid argument error: */ + rval = EINVAL; + break; + } + + /* Unlock the condition variable structure: */ + _SPINUNLOCK(&(*cond)->lock); + + /* + * Undefer and handle pending signals, yielding if + * necessary: + */ + _thread_kern_sig_undefer(); + } + + /* Return the completion status: */ + return (rval); +} + +int +_pthread_cond_broadcast(pthread_cond_t * cond) +{ + int rval = 0; + pthread_t pthread; + + if (cond == NULL) + rval = EINVAL; + /* + * If the condition variable is statically initialized, perform dynamic + * initialization. + */ + else if (*cond != NULL || (rval = pthread_cond_init(cond, NULL)) == 0) { + /* + * Defer signals to protect the scheduling queues + * from access by the signal handler: + */ + _thread_kern_sig_defer(); + + /* Lock the condition variable structure: */ + _SPINLOCK(&(*cond)->lock); + + /* Process according to condition variable type: */ + switch ((*cond)->c_type) { + /* Fast condition variable: */ + case COND_TYPE_FAST: + /* Increment the sequence number: */ + (*cond)->c_seqno++; + + /* + * Enter a loop to bring all threads off the + * condition queue: + */ + while ((pthread = cond_queue_deq(*cond)) != NULL) { + /* + * Unless the thread is currently suspended, + * allow it to run. If the thread is suspended, + * make a note that the thread isn't in a wait + * queue any more. + */ + if (pthread->state != PS_SUSPENDED) + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + else + pthread->suspended = SUSP_NOWAIT; + } + + /* There are no more waiting threads: */ + (*cond)->c_mutex = NULL; + break; + + /* Trap invalid condition variable types: */ + default: + /* Return an invalid argument error: */ + rval = EINVAL; + break; + } + + /* Unlock the condition variable structure: */ + _SPINUNLOCK(&(*cond)->lock); + + /* + * Undefer and handle pending signals, yielding if + * necessary: + */ + _thread_kern_sig_undefer(); + } + + /* Return the completion status: */ + return (rval); +} + +void +_cond_wait_backout(pthread_t pthread) +{ + pthread_cond_t cond; + + cond = pthread->data.cond; + if (cond != NULL) { + /* + * Defer signals to protect the scheduling queues + * from access by the signal handler: + */ + _thread_kern_sig_defer(); + + /* Lock the condition variable structure: */ + _SPINLOCK(&cond->lock); + + /* Process according to condition variable type: */ + switch (cond->c_type) { + /* Fast condition variable: */ + case COND_TYPE_FAST: + cond_queue_remove(cond, pthread); + + /* Check for no more waiters: */ + if (TAILQ_FIRST(&cond->c_queue) == NULL) + cond->c_mutex = NULL; + break; + + default: + break; + } + + /* Unlock the condition variable structure: */ + _SPINUNLOCK(&cond->lock); + + /* + * Undefer and handle pending signals, yielding if + * necessary: + */ + _thread_kern_sig_undefer(); + } +} + +/* + * Dequeue a waiting thread from the head of a condition queue in + * descending priority order. + */ +static inline pthread_t +cond_queue_deq(pthread_cond_t cond) +{ + pthread_t pthread; + + while ((pthread = TAILQ_FIRST(&cond->c_queue)) != NULL) { + TAILQ_REMOVE(&cond->c_queue, pthread, sqe); + pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ; + if ((pthread->timeout == 0) && (pthread->interrupted == 0)) + /* + * Only exit the loop when we find a thread + * that hasn't timed out or been canceled; + * those threads are already running and don't + * need their run state changed. + */ + break; + } + + return(pthread); +} + +/* + * Remove a waiting thread from a condition queue in descending priority + * order. + */ +static inline void +cond_queue_remove(pthread_cond_t cond, pthread_t pthread) +{ + /* + * Because pthread_cond_timedwait() can timeout as well + * as be signaled by another thread, it is necessary to + * guard against removing the thread from the queue if + * it isn't in the queue. + */ + if (pthread->flags & PTHREAD_FLAGS_IN_CONDQ) { + TAILQ_REMOVE(&cond->c_queue, pthread, sqe); + pthread->flags &= ~PTHREAD_FLAGS_IN_CONDQ; + } +} + +/* + * Enqueue a waiting thread to a condition queue in descending priority + * order. + */ +static inline void +cond_queue_enq(pthread_cond_t cond, pthread_t pthread) +{ + pthread_t tid = TAILQ_LAST(&cond->c_queue, cond_head); + + PTHREAD_ASSERT_NOT_IN_SYNCQ(pthread); + + /* + * For the common case of all threads having equal priority, + * we perform a quick check against the priority of the thread + * at the tail of the queue. + */ + if ((tid == NULL) || (pthread->active_priority <= tid->active_priority)) + TAILQ_INSERT_TAIL(&cond->c_queue, pthread, sqe); + else { + tid = TAILQ_FIRST(&cond->c_queue); + while (pthread->active_priority <= tid->active_priority) + tid = TAILQ_NEXT(tid, sqe); + TAILQ_INSERT_BEFORE(tid, pthread, sqe); + } + pthread->flags |= PTHREAD_FLAGS_IN_CONDQ; + pthread->data.cond = cond; +} diff --git a/lib/libc_r/uthread/uthread_condattr_destroy.c b/lib/libc_r/uthread/uthread_condattr_destroy.c new file mode 100644 index 0000000..3a05487 --- /dev/null +++ b/lib/libc_r/uthread/uthread_condattr_destroy.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1997 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <stdlib.h> +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_condattr_destroy, pthread_condattr_destroy); + +int +_pthread_condattr_destroy(pthread_condattr_t *attr) +{ + int ret; + if (attr == NULL || *attr == NULL) { + ret = EINVAL; + } else { + free(*attr); + *attr = NULL; + ret = 0; + } + return(ret); +} diff --git a/lib/libc_r/uthread/uthread_condattr_init.c b/lib/libc_r/uthread/uthread_condattr_init.c new file mode 100644 index 0000000..cfc1e4a --- /dev/null +++ b/lib/libc_r/uthread/uthread_condattr_init.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1997 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_condattr_init, pthread_condattr_init); + +int +_pthread_condattr_init(pthread_condattr_t *attr) +{ + int ret; + pthread_condattr_t pattr; + + if ((pattr = (pthread_condattr_t) + malloc(sizeof(struct pthread_cond_attr))) == NULL) { + ret = ENOMEM; + } else { + memcpy(pattr, &pthread_condattr_default, + sizeof(struct pthread_cond_attr)); + *attr = pattr; + ret = 0; + } + return(ret); +} diff --git a/lib/libc_r/uthread/uthread_connect.c b/lib/libc_r/uthread/uthread_connect.c new file mode 100644 index 0000000..9612e1f --- /dev/null +++ b/lib/libc_r/uthread/uthread_connect.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <fcntl.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_connect, connect); + +int +_connect(int fd, const struct sockaddr * name, socklen_t namelen) +{ + struct pthread *curthread = _get_curthread(); + struct sockaddr tmpname; + int errnolen, ret, tmpnamelen; + + if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) { + if ((ret = __sys_connect(fd, name, namelen)) < 0) { + if (!(_thread_fd_table[fd]->flags & O_NONBLOCK) && + ((errno == EWOULDBLOCK) || (errno == EINPROGRESS) || + (errno == EALREADY) || (errno == EAGAIN))) { + curthread->data.fd.fd = fd; + + /* Set the timeout: */ + _thread_kern_set_timeout(NULL); + _thread_kern_sched_state(PS_FDW_WAIT, __FILE__, __LINE__); + + tmpnamelen = sizeof(tmpname); + /* 0 now lets see if it really worked */ + if (((ret = __sys_getpeername(fd, &tmpname, &tmpnamelen)) < 0) && (errno == ENOTCONN)) { + + /* + * Get the error, this function + * should not fail + */ + errnolen = sizeof(errno); + __sys_getsockopt(fd, SOL_SOCKET, SO_ERROR, &errno, &errnolen); + } + } else { + ret = -1; + } + } + _FD_UNLOCK(fd, FD_RDWR); + } + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_creat.c b/lib/libc_r/uthread/uthread_creat.c new file mode 100644 index 0000000..92da971 --- /dev/null +++ b/lib/libc_r/uthread/uthread_creat.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. + * 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(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) 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. + * + * $FreeBSD$ + */ + +#include <fcntl.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(___creat, creat); + +int +___creat(const char *path, mode_t mode) +{ + int ret; + + _thread_enter_cancellation_point(); + ret = __creat(path, mode); + _thread_leave_cancellation_point(); + + return ret; +} diff --git a/lib/libc_r/uthread/uthread_create.c b/lib/libc_r/uthread/uthread_create.c new file mode 100644 index 0000000..f846789 --- /dev/null +++ b/lib/libc_r/uthread/uthread_create.c @@ -0,0 +1,267 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <fcntl.h> +#include <unistd.h> +#include <stddef.h> +#include <sys/time.h> +#include <machine/reg.h> +#include <pthread.h> +#include "pthread_private.h" +#include "libc_private.h" + +static u_int64_t next_uniqueid = 1; + +#define OFF(f) offsetof(struct pthread, f) +int _thread_next_offset = OFF(tle.tqe_next); +int _thread_uniqueid_offset = OFF(uniqueid); +int _thread_state_offset = OFF(state); +int _thread_name_offset = OFF(name); +int _thread_ctx_offset = OFF(ctx); +#undef OFF + +int _thread_PS_RUNNING_value = PS_RUNNING; +int _thread_PS_DEAD_value = PS_DEAD; + +__weak_reference(_pthread_create, pthread_create); + +int +_pthread_create(pthread_t * thread, const pthread_attr_t * attr, + void *(*start_routine) (void *), void *arg) +{ + struct pthread *curthread = _get_curthread(); + struct itimerval itimer; + int f_gc = 0; + int ret = 0; + pthread_t gc_thread; + pthread_t new_thread; + pthread_attr_t pattr; + void *stack; + + /* + * Locking functions in libc are required when there are + * threads other than the initial thread. + */ + __isthreaded = 1; + + /* Allocate memory for the thread structure: */ + if ((new_thread = (pthread_t) malloc(sizeof(struct pthread))) == NULL) { + /* Insufficient memory to create a thread: */ + ret = EAGAIN; + } else { + /* Check if default thread attributes are required: */ + if (attr == NULL || *attr == NULL) { + /* Use the default thread attributes: */ + pattr = &pthread_attr_default; + } else { + pattr = *attr; + } + /* Check if a stack was specified in the thread attributes: */ + if ((stack = pattr->stackaddr_attr) != NULL) { + } + /* Allocate a stack: */ + else { + stack = _thread_stack_alloc(pattr->stacksize_attr, + pattr->guardsize_attr); + if (stack == NULL) { + ret = EAGAIN; + free(new_thread); + } + } + + /* Check for errors: */ + if (ret != 0) { + } else { + /* Initialise the thread structure: */ + memset(new_thread, 0, sizeof(struct pthread)); + new_thread->slice_usec = -1; + new_thread->stack = stack; + new_thread->start_routine = start_routine; + new_thread->arg = arg; + + new_thread->cancelflags = PTHREAD_CANCEL_ENABLE | + PTHREAD_CANCEL_DEFERRED; + + /* + * Write a magic value to the thread structure + * to help identify valid ones: + */ + new_thread->magic = PTHREAD_MAGIC; + + /* Initialise the thread for signals: */ + new_thread->sigmask = curthread->sigmask; + new_thread->sigmask_seqno = 0; + + /* Initialize the signal frame: */ + new_thread->curframe = NULL; + + /* Initialise the jump buffer: */ + _setjmp(new_thread->ctx.jb); + + /* + * Set up new stack frame so that it looks like it + * returned from a longjmp() to the beginning of + * _thread_start(). + */ + SET_RETURN_ADDR_JB(new_thread->ctx.jb, _thread_start); + + /* The stack starts high and builds down: */ + SET_STACK_JB(new_thread->ctx.jb, + (long)new_thread->stack + pattr->stacksize_attr + - sizeof(double)); + + /* Copy the thread attributes: */ + memcpy(&new_thread->attr, pattr, sizeof(struct pthread_attr)); + + /* + * Check if this thread is to inherit the scheduling + * attributes from its parent: + */ + if (new_thread->attr.flags & PTHREAD_INHERIT_SCHED) { + /* Copy the scheduling attributes: */ + new_thread->base_priority = + curthread->base_priority & + ~PTHREAD_SIGNAL_PRIORITY; + new_thread->attr.prio = + curthread->base_priority & + ~PTHREAD_SIGNAL_PRIORITY; + new_thread->attr.sched_policy = + curthread->attr.sched_policy; + } else { + /* + * Use just the thread priority, leaving the + * other scheduling attributes as their + * default values: + */ + new_thread->base_priority = + new_thread->attr.prio; + } + new_thread->active_priority = new_thread->base_priority; + new_thread->inherited_priority = 0; + + /* Initialize joiner to NULL (no joiner): */ + new_thread->joiner = NULL; + + /* Initialize the mutex queue: */ + TAILQ_INIT(&new_thread->mutexq); + + /* Initialise hooks in the thread structure: */ + new_thread->specific = NULL; + new_thread->cleanup = NULL; + new_thread->flags = 0; + new_thread->poll_data.nfds = 0; + new_thread->poll_data.fds = NULL; + new_thread->continuation = NULL; + + /* + * Defer signals to protect the scheduling queues + * from access by the signal handler: + */ + _thread_kern_sig_defer(); + + /* + * Initialise the unique id which GDB uses to + * track threads. + */ + new_thread->uniqueid = next_uniqueid++; + + /* + * Check if the garbage collector thread + * needs to be started. + */ + f_gc = (TAILQ_FIRST(&_thread_list) == _thread_initial); + + /* Add the thread to the linked list of all threads: */ + TAILQ_INSERT_HEAD(&_thread_list, new_thread, tle); + + if (pattr->suspend == PTHREAD_CREATE_SUSPENDED) + new_thread->state = PS_SUSPENDED; + else { + new_thread->state = PS_RUNNING; + PTHREAD_PRIOQ_INSERT_TAIL(new_thread); + } + + /* + * Undefer and handle pending signals, yielding + * if necessary. + */ + _thread_kern_sig_undefer(); + + /* Return a pointer to the thread structure: */ + (*thread) = new_thread; + + if (f_gc != 0) { + /* Install the scheduling timer: */ + itimer.it_interval.tv_sec = 0; + itimer.it_interval.tv_usec = _clock_res_usec; + itimer.it_value = itimer.it_interval; + if (setitimer(_ITIMER_SCHED_TIMER, &itimer, + NULL) != 0) + PANIC("Cannot set interval timer"); + } + + /* Schedule the new user thread: */ + _thread_kern_sched(NULL); + + /* + * Start a garbage collector thread + * if necessary. + */ + if (f_gc && pthread_create(&gc_thread,NULL, + _thread_gc,NULL) != 0) + PANIC("Can't create gc thread"); + + } + } + + /* Return the status: */ + return (ret); +} + +void +_thread_start(void) +{ + struct pthread *curthread = _get_curthread(); + + /* We just left the scheduler via longjmp: */ + _thread_kern_in_sched = 0; + + /* Run the current thread's start routine with argument: */ + pthread_exit(curthread->start_routine(curthread->arg)); + + /* This point should never be reached. */ + PANIC("Thread has resumed after exit"); +} diff --git a/lib/libc_r/uthread/uthread_detach.c b/lib/libc_r/uthread/uthread_detach.c new file mode 100644 index 0000000..298fdb4 --- /dev/null +++ b/lib/libc_r/uthread/uthread_detach.c @@ -0,0 +1,90 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_detach, pthread_detach); + +int +_pthread_detach(pthread_t pthread) +{ + int rval = 0; + + /* Check for invalid calling parameters: */ + if (pthread == NULL || pthread->magic != PTHREAD_MAGIC) + /* Return an invalid argument error: */ + rval = EINVAL; + + /* Check if the thread has not been detached: */ + else if ((pthread->attr.flags & PTHREAD_DETACHED) == 0) { + /* Flag the thread as detached: */ + pthread->attr.flags |= PTHREAD_DETACHED; + + /* + * Defer signals to protect the scheduling queues from + * access by the signal handler: + */ + _thread_kern_sig_defer(); + + /* Check if there is a joiner: */ + if (pthread->joiner != NULL) { + struct pthread *joiner = pthread->joiner; + + /* Make the thread runnable: */ + PTHREAD_NEW_STATE(joiner, PS_RUNNING); + + /* Set the return value for the woken thread: */ + joiner->join_status.error = ESRCH; + joiner->join_status.ret = NULL; + joiner->join_status.thread = NULL; + + /* + * Disconnect the joiner from the thread being detached: + */ + pthread->joiner = NULL; + } + + /* + * Undefer and handle pending signals, yielding if a + * scheduling signal occurred while in the critical region. + */ + _thread_kern_sig_undefer(); + } else + /* Return an error: */ + rval = EINVAL; + + /* Return the completion status: */ + return (rval); +} diff --git a/lib/libc_r/uthread/uthread_dup.c b/lib/libc_r/uthread/uthread_dup.c new file mode 100644 index 0000000..9fc2e58 --- /dev/null +++ b/lib/libc_r/uthread/uthread_dup.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <unistd.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_dup, dup); + +int +_dup(int fd) +{ + int ret; + + /* Lock the file descriptor: */ + if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) { + /* Perform the 'dup' syscall: */ + if ((ret = __sys_dup(fd)) < 0) { + } + /* Initialise the file descriptor table entry: */ + else if (_thread_fd_table_init(ret) != 0) { + /* Quietly close the file: */ + __sys_close(ret); + + /* Reset the file descriptor: */ + ret = -1; + } else { + /* + * Save the file open flags so that they can be + * checked later: + */ + _thread_fd_table[ret]->flags = _thread_fd_table[fd]->flags; + } + + /* Unlock the file descriptor: */ + _FD_UNLOCK(fd, FD_RDWR); + } + /* Return the completion status: */ + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_dup2.c b/lib/libc_r/uthread/uthread_dup2.c new file mode 100644 index 0000000..af0e32a --- /dev/null +++ b/lib/libc_r/uthread/uthread_dup2.c @@ -0,0 +1,87 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <unistd.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_dup2, dup2); + +int +_dup2(int fd, int newfd) +{ + int ret; + int newfd_opened; + + /* Check if the file descriptor is out of range: */ + if (newfd < 0 || newfd >= _thread_dtablesize || + newfd == _thread_kern_pipe[0] || newfd == _thread_kern_pipe[1]) { + /* Return a bad file descriptor error: */ + errno = EBADF; + ret = -1; + } + + /* Lock the file descriptor: */ + else if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) { + /* Lock the file descriptor: */ + if (!(newfd_opened = (_thread_fd_table[newfd] != NULL)) || + (ret = _FD_LOCK(newfd, FD_RDWR, NULL)) == 0) { + /* Perform the 'dup2' syscall: */ + if ((ret = __sys_dup2(fd, newfd)) < 0) { + } + /* Initialise the file descriptor table entry: */ + else if (_thread_fd_table_init(ret) != 0) { + /* Quietly close the file: */ + __sys_close(ret); + + /* Reset the file descriptor: */ + ret = -1; + } else { + /* + * Save the file open flags so that they can + * be checked later: + */ + _thread_fd_table[ret]->flags = _thread_fd_table[fd]->flags; + } + + /* Unlock the file descriptor: */ + if (newfd_opened) + _FD_UNLOCK(newfd, FD_RDWR); + } + /* Unlock the file descriptor: */ + _FD_UNLOCK(fd, FD_RDWR); + } + /* Return the completion status: */ + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_equal.c b/lib/libc_r/uthread/uthread_equal.c new file mode 100644 index 0000000..0dfb63d --- /dev/null +++ b/lib/libc_r/uthread/uthread_equal.c @@ -0,0 +1,44 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_equal, pthread_equal); + +int +_pthread_equal(pthread_t t1, pthread_t t2) +{ + /* Compare the two thread pointers: */ + return (t1 == t2); +} diff --git a/lib/libc_r/uthread/uthread_execve.c b/lib/libc_r/uthread/uthread_execve.c new file mode 100644 index 0000000..082814d --- /dev/null +++ b/lib/libc_r/uthread/uthread_execve.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <fcntl.h> +#include <unistd.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_execve, execve); + +int +_execve(const char *name, char *const * argv, char *const * envp) +{ + struct pthread *curthread = _get_curthread(); + 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_SCHED_TIMER, &itimer, NULL); + + /* Close the pthread kernel pipe: */ + __sys_close(_thread_kern_pipe[0]); + __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 = __sys_fcntl(i, F_GETFL, NULL); + /* Clear the nonblocking file descriptor flag: */ + __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: */ + if (i == SIGKILL || i == SIGSTOP) { + /* Don't do anything with these signals. */ + } else { + /* Check if ignoring this signal: */ + if (_thread_sigact[i - 1].sa_handler == SIG_IGN) { + /* Continue to ignore this signal: */ + act.sa_handler = SIG_IGN; + } else { + /* Use the default handler for this signal: */ + act.sa_handler = SIG_DFL; + } + + /* Copy the mask and flags for this signal: */ + act.sa_mask = _thread_sigact[i - 1].sa_mask; + act.sa_flags = _thread_sigact[i - 1].sa_flags; + + /* Change the signal action for the process: */ + __sys_sigaction(i, &act, &oact); + } + } + + /* Set the signal mask: */ + __sys_sigprocmask(SIG_SETMASK, &curthread->sigmask, NULL); + + /* Execute the process: */ + ret = __sys_execve(name, argv, envp); + + /* Return the completion status: */ + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_exit.c b/lib/libc_r/uthread/uthread_exit.c new file mode 100644 index 0000000..c9513cf --- /dev/null +++ b/lib/libc_r/uthread/uthread_exit.c @@ -0,0 +1,241 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <unistd.h> +#include <fcntl.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <pthread.h> +#include "pthread_private.h" + +#define FLAGS_IN_SCHEDQ \ + (PTHREAD_FLAGS_IN_PRIOQ|PTHREAD_FLAGS_IN_WAITQ|PTHREAD_FLAGS_IN_WORKQ) + +__weak_reference(_pthread_exit, pthread_exit); + +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_SCHED_TIMER, &itimer, NULL); + + /* Close the pthread kernel pipe: */ + __sys_close(_thread_kern_pipe[0]); + __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 = __sys_fcntl(i, F_GETFL, NULL); + /* Clear the nonblocking file descriptor flag: */ + __sys_fcntl(i, F_SETFL, flags & ~O_NONBLOCK); + } + } + + /* Call the _exit syscall: */ + __sys_exit(status); +} + +void +_thread_exit(char *fname, int lineno, char *string) +{ + char s[256]; + + /* Prepare an error message string: */ + snprintf(s, sizeof(s), + "Fatal error '%s' at line %d in file %s (errno = %d)\n", + string, lineno, fname, errno); + + /* Write the string to the standard error file descriptor: */ + __sys_write(2, s, strlen(s)); + + /* Force this process to exit: */ + /* XXX - Do we want abort to be conditional on _PTHREADS_INVARIANTS? */ +#if defined(_PTHREADS_INVARIANTS) + abort(); +#else + __sys_exit(1); +#endif +} + +/* + * Only called when a thread is cancelled. It may be more useful + * to call it from pthread_exit() if other ways of asynchronous or + * abnormal thread termination can be found. + */ +void +_thread_exit_cleanup(void) +{ + struct pthread *curthread = _get_curthread(); + + /* + * POSIX states that cancellation/termination of a thread should + * not release any visible resources (such as mutexes) and that + * it is the applications responsibility. Resources that are + * internal to the threads library, including file and fd locks, + * are not visible to the application and need to be released. + */ + /* Unlock all owned fd locks: */ + _thread_fd_unlock_owned(curthread); + + /* Unlock all private mutexes: */ + _mutex_unlock_private(curthread); + + /* + * This still isn't quite correct because we don't account + * for held spinlocks (see libc/stdlib/malloc.c). + */ +} + +void +_pthread_exit(void *status) +{ + struct pthread *curthread = _get_curthread(); + pthread_t pthread; + + /* Check if this thread is already in the process of exiting: */ + if ((curthread->flags & PTHREAD_EXITING) != 0) { + char msg[128]; + snprintf(msg, sizeof(msg), "Thread %p has called pthread_exit() from a destructor. POSIX 1003.1 1996 s16.2.5.2 does not allow this!",curthread); + PANIC(msg); + } + + /* Flag this thread as exiting: */ + curthread->flags |= PTHREAD_EXITING; + + /* Save the return value: */ + curthread->ret = status; + + while (curthread->cleanup != NULL) { + pthread_cleanup_pop(1); + } + if (curthread->attr.cleanup_attr != NULL) { + curthread->attr.cleanup_attr(curthread->attr.arg_attr); + } + /* Check if there is thread specific data: */ + if (curthread->specific != NULL) { + /* Run the thread-specific data destructors: */ + _thread_cleanupspecific(); + } + + /* Free thread-specific poll_data structure, if allocated: */ + if (curthread->poll_data.fds != NULL) { + free(curthread->poll_data.fds); + curthread->poll_data.fds = NULL; + } + + /* + * Lock the garbage collector mutex to ensure that the garbage + * collector is not using the dead thread list. + */ + if (pthread_mutex_lock(&_gc_mutex) != 0) + PANIC("Cannot lock gc mutex"); + + /* Add this thread to the list of dead threads. */ + TAILQ_INSERT_HEAD(&_dead_list, curthread, dle); + + /* + * Signal the garbage collector thread that there is something + * to clean up. + */ + if (pthread_cond_signal(&_gc_cond) != 0) + PANIC("Cannot signal gc cond"); + + /* + * Avoid a race condition where a scheduling signal can occur + * causing the garbage collector thread to run. If this happens, + * the current thread can be cleaned out from under us. + */ + _thread_kern_sig_defer(); + + /* Unlock the garbage collector mutex: */ + if (pthread_mutex_unlock(&_gc_mutex) != 0) + PANIC("Cannot unlock gc mutex"); + + /* Check if there is a thread joining this one: */ + if (curthread->joiner != NULL) { + pthread = curthread->joiner; + curthread->joiner = NULL; + + switch (pthread->suspended) { + case SUSP_JOIN: + /* + * The joining thread is suspended. Change the + * suspension state to make the thread runnable when it + * is resumed: + */ + pthread->suspended = SUSP_NO; + break; + case SUSP_NO: + /* Make the joining thread runnable: */ + PTHREAD_NEW_STATE(pthread, PS_RUNNING); + break; + default: + PANIC("Unreachable code reached"); + } + + /* Set the return value for the joining thread: */ + pthread->join_status.ret = curthread->ret; + pthread->join_status.error = 0; + pthread->join_status.thread = NULL; + + /* Make this thread collectable by the garbage collector. */ + PTHREAD_ASSERT(((curthread->attr.flags & PTHREAD_DETACHED) == + 0), "Cannot join a detached thread"); + curthread->attr.flags |= PTHREAD_DETACHED; + } + + /* Remove this thread from the thread list: */ + TAILQ_REMOVE(&_thread_list, curthread, tle); + + /* This thread will never be re-scheduled. */ + _thread_kern_sched_state(PS_DEAD, __FILE__, __LINE__); + + /* This point should not be reached. */ + PANIC("Dead thread has resumed"); +} diff --git a/lib/libc_r/uthread/uthread_fchflags.c b/lib/libc_r/uthread/uthread_fchflags.c new file mode 100644 index 0000000..cd076e2 --- /dev/null +++ b/lib/libc_r/uthread/uthread_fchflags.c @@ -0,0 +1,24 @@ +/* + * David Leonard <d@openbsd.org>, 1999. Public Domain. + * + * $OpenBSD: uthread_fchflags.c,v 1.1 1999/01/08 05:42:18 d Exp $ + * $FreeBSD$ + */ + +#include <sys/stat.h> +#include <unistd.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_fchflags, fchflags); +int +_fchflags(int fd, u_long flags) +{ + int ret; + + if ((ret = _FD_LOCK(fd, FD_WRITE, NULL)) == 0) { + ret = __sys_fchflags(fd, flags); + _FD_UNLOCK(fd, FD_WRITE); + } + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_fchmod.c b/lib/libc_r/uthread/uthread_fchmod.c new file mode 100644 index 0000000..05dea24 --- /dev/null +++ b/lib/libc_r/uthread/uthread_fchmod.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <sys/types.h> +#include <sys/stat.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_fchmod, fchmod); + +int +_fchmod(int fd, mode_t mode) +{ + int ret; + + if ((ret = _FD_LOCK(fd, FD_WRITE, NULL)) == 0) { + ret = __sys_fchmod(fd, mode); + _FD_UNLOCK(fd, FD_WRITE); + } + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_fchown.c b/lib/libc_r/uthread/uthread_fchown.c new file mode 100644 index 0000000..5b27bcb --- /dev/null +++ b/lib/libc_r/uthread/uthread_fchown.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <sys/types.h> +#include <unistd.h> +#include <dirent.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_fchown, fchown); + +int +_fchown(int fd, uid_t owner, gid_t group) +{ + int ret; + + if ((ret = _FD_LOCK(fd, FD_WRITE, NULL)) == 0) { + ret = __sys_fchown(fd, owner, group); + _FD_UNLOCK(fd, FD_WRITE); + } + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_fcntl.c b/lib/libc_r/uthread/uthread_fcntl.c new file mode 100644 index 0000000..1d12c0e --- /dev/null +++ b/lib/libc_r/uthread/uthread_fcntl.c @@ -0,0 +1,170 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <stdarg.h> +#include <unistd.h> +#include <fcntl.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(__fcntl, fcntl); + +int +_fcntl(int fd, int cmd,...) +{ + int flags = 0; + int nonblock; + int oldfd; + int ret; + va_list ap; + + /* Lock the file descriptor: */ + if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) { + /* Initialise the variable argument list: */ + va_start(ap, cmd); + + /* Process according to file control command type: */ + switch (cmd) { + /* Duplicate a file descriptor: */ + case F_DUPFD: + /* + * Get the file descriptor that the caller wants to + * use: + */ + oldfd = va_arg(ap, int); + + /* Initialise the file descriptor table entry: */ + if ((ret = __sys_fcntl(fd, cmd, oldfd)) < 0) { + } + /* Initialise the file descriptor table entry: */ + else if (_thread_fd_table_init(ret) != 0) { + /* Quietly close the file: */ + __sys_close(ret); + + /* Reset the file descriptor: */ + ret = -1; + } else { + /* + * Save the file open flags so that they can + * be checked later: + */ + _thread_fd_table[ret]->flags = _thread_fd_table[fd]->flags; + } + break; + case F_SETFD: + flags = va_arg(ap, int); + ret = __sys_fcntl(fd, cmd, flags); + break; + case F_GETFD: + ret = __sys_fcntl(fd, cmd, 0); + break; + case F_GETFL: + ret = _thread_fd_table[fd]->flags; + break; + case F_SETFL: + /* + * Get the file descriptor flags passed by the + * caller: + */ + flags = va_arg(ap, int); + + /* + * Check if the user wants a non-blocking file + * descriptor: + */ + nonblock = flags & O_NONBLOCK; + + /* Set the file descriptor flags: */ + if ((ret = __sys_fcntl(fd, cmd, flags | O_NONBLOCK)) != 0) { + + /* Get the flags so that we behave like the kernel: */ + } else if ((flags = __sys_fcntl(fd, + F_GETFL, 0)) == -1) { + /* Error getting flags: */ + ret = -1; + + /* + * Check if the file descriptor is non-blocking + * with respect to the user: + */ + } else if (nonblock) + /* A non-blocking descriptor: */ + _thread_fd_table[fd]->flags = flags | O_NONBLOCK; + else + /* Save the flags: */ + _thread_fd_table[fd]->flags = flags & ~O_NONBLOCK; + break; + default: + /* Might want to make va_arg use a union */ + ret = __sys_fcntl(fd, cmd, va_arg(ap, void *)); + break; + } + + /* Free variable arguments: */ + va_end(ap); + + /* Unlock the file descriptor: */ + _FD_UNLOCK(fd, FD_RDWR); + } + /* Return the completion status: */ + return (ret); +} + +int +__fcntl(int fd, int cmd,...) +{ + int ret; + va_list ap; + + _thread_enter_cancellation_point(); + + va_start(ap, cmd); + switch (cmd) { + case F_DUPFD: + case F_SETFD: + case F_SETFL: + ret = _fcntl(fd, cmd, va_arg(ap, int)); + break; + case F_GETFD: + case F_GETFL: + ret = _fcntl(fd, cmd); + break; + default: + ret = _fcntl(fd, cmd, va_arg(ap, void *)); + } + va_end(ap); + + _thread_leave_cancellation_point(); + + return ret; +} diff --git a/lib/libc_r/uthread/uthread_fd.c b/lib/libc_r/uthread/uthread_fd.c new file mode 100644 index 0000000..060515a --- /dev/null +++ b/lib/libc_r/uthread/uthread_fd.c @@ -0,0 +1,1041 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + * + */ +#include <errno.h> +#include <fcntl.h> +#include <stdlib.h> +#include <string.h> +#include <pthread.h> +#include "pthread_private.h" + +#define FDQ_INSERT(q,p) \ +do { \ + TAILQ_INSERT_TAIL(q,p,qe); \ + p->flags |= PTHREAD_FLAGS_IN_FDQ; \ +} while (0) + +#define FDQ_REMOVE(q,p) \ +do { \ + if ((p->flags & PTHREAD_FLAGS_IN_FDQ) != 0) { \ + TAILQ_REMOVE(q,p,qe); \ + p->flags &= ~PTHREAD_FLAGS_IN_FDQ; \ + } \ +} while (0) + + +/* Static variables: */ +static spinlock_t fd_table_lock = _SPINLOCK_INITIALIZER; + +/* Prototypes: */ +#ifdef _FDLOCKS_ENABLED +static inline pthread_t fd_next_reader(int fd); +static inline pthread_t fd_next_writer(int fd); +#endif + + +/* + * This function *must* return -1 and set the thread specific errno + * as a system call. This is because the error return from this + * function is propagated directly back from thread-wrapped system + * calls. + */ + +int +_thread_fd_table_init(int fd) +{ + int ret = 0; + struct fd_table_entry *entry; + int saved_errno; + + if (_thread_initial == NULL) + _thread_init(); + + /* Check if the file descriptor is out of range: */ + if (fd < 0 || fd >= _thread_dtablesize) { + /* Return a bad file descriptor error: */ + errno = EBADF; + ret = -1; + } + + /* + * Check if memory has already been allocated for this file + * descriptor: + */ + else if (_thread_fd_table[fd] != NULL) { + /* Memory has already been allocated. */ + + /* Allocate memory for the file descriptor table entry: */ + } else if ((entry = (struct fd_table_entry *) + malloc(sizeof(struct fd_table_entry))) == NULL) { + /* Return an insufficient memory error: */ + errno = ENOMEM; + ret = -1; + } else { + /* Initialise the file locks: */ + memset(&entry->lock, 0, sizeof(entry->lock)); + entry->r_owner = NULL; + entry->w_owner = NULL; + entry->r_fname = NULL; + entry->w_fname = NULL; + entry->r_lineno = 0; + entry->w_lineno = 0; + entry->r_lockcount = 0; + entry->w_lockcount = 0; + + /* Initialise the read/write queues: */ + TAILQ_INIT(&entry->r_queue); + TAILQ_INIT(&entry->w_queue); + + /* Get the flags for the file: */ + if (((fd >= 3) || (_pthread_stdio_flags[fd] == -1)) && + (entry->flags = __sys_fcntl(fd, F_GETFL, 0)) == -1) { + ret = -1; + } + else { + /* Check if a stdio descriptor: */ + if ((fd < 3) && (_pthread_stdio_flags[fd] != -1)) + /* + * Use the stdio flags read by + * _pthread_init() to avoid + * mistaking the non-blocking + * flag that, when set on one + * stdio fd, is set on all stdio + * fds. + */ + entry->flags = _pthread_stdio_flags[fd]; + + /* + * Make the file descriptor non-blocking. + * This might fail if the device driver does + * not support non-blocking calls, or if the + * driver is naturally non-blocking. + */ + saved_errno = errno; + __sys_fcntl(fd, F_SETFL, + entry->flags | O_NONBLOCK); + errno = saved_errno; + + /* Lock the file descriptor table: */ + _SPINLOCK(&fd_table_lock); + + /* + * Check if another thread allocated the + * file descriptor entry while this thread + * was doing the same thing. The table wasn't + * kept locked during this operation because + * it has the potential to recurse. + */ + if (_thread_fd_table[fd] == NULL) { + /* This thread wins: */ + _thread_fd_table[fd] = entry; + entry = NULL; + } + + /* Unlock the file descriptor table: */ + _SPINUNLOCK(&fd_table_lock); + } + + /* + * Check if another thread initialised the table entry + * before this one could: + */ + if (entry != NULL) + /* + * Throw away the table entry that this thread + * prepared. The other thread wins. + */ + free(entry); + } + + /* Return the completion status: */ + return (ret); +} + +#ifdef _FDLOCKS_ENABLED +void +_thread_fd_unlock(int fd, int lock_type) +{ + struct pthread *curthread = _get_curthread(); + int ret; + + /* + * Check that the file descriptor table is initialised for this + * entry: + */ + if ((ret = _thread_fd_table_init(fd)) == 0) { + /* + * Defer signals to protect the scheduling queues from + * access by the signal handler: + */ + _thread_kern_sig_defer(); + + /* + * Lock the file descriptor table entry to prevent + * other threads for clashing with the current + * thread's accesses: + */ + _SPINLOCK(&_thread_fd_table[fd]->lock); + + /* Check if the running thread owns the read lock: */ + if (_thread_fd_table[fd]->r_owner == curthread) { + /* Check the file descriptor and lock types: */ + if (lock_type == FD_READ || lock_type == FD_RDWR) { + /* + * Decrement the read lock count for the + * running thread: + */ + _thread_fd_table[fd]->r_lockcount--; + + /* + * Check if the running thread still has read + * locks on this file descriptor: + */ + if (_thread_fd_table[fd]->r_lockcount != 0) { + } + /* + * Get the next thread in the queue for a + * read lock on this file descriptor: + */ + else if ((_thread_fd_table[fd]->r_owner = fd_next_reader(fd)) == NULL) { + } else { + /* Remove this thread from the queue: */ + FDQ_REMOVE(&_thread_fd_table[fd]->r_queue, + _thread_fd_table[fd]->r_owner); + + /* + * Set the state of the new owner of + * the thread to running: + */ + PTHREAD_NEW_STATE(_thread_fd_table[fd]->r_owner,PS_RUNNING); + + /* + * Reset the number of read locks. + * This will be incremented by the + * new owner of the lock when it sees + * that it has the lock. + */ + _thread_fd_table[fd]->r_lockcount = 0; + } + } + } + /* Check if the running thread owns the write lock: */ + if (_thread_fd_table[fd]->w_owner == curthread) { + /* Check the file descriptor and lock types: */ + if (lock_type == FD_WRITE || lock_type == FD_RDWR) { + /* + * Decrement the write lock count for the + * running thread: + */ + _thread_fd_table[fd]->w_lockcount--; + + /* + * Check if the running thread still has + * write locks on this file descriptor: + */ + if (_thread_fd_table[fd]->w_lockcount != 0) { + } + /* + * Get the next thread in the queue for a + * write lock on this file descriptor: + */ + else if ((_thread_fd_table[fd]->w_owner = fd_next_writer(fd)) == NULL) { + } else { + /* Remove this thread from the queue: */ + FDQ_REMOVE(&_thread_fd_table[fd]->w_queue, + _thread_fd_table[fd]->w_owner); + + /* + * Set the state of the new owner of + * the thread to running: + */ + PTHREAD_NEW_STATE(_thread_fd_table[fd]->w_owner,PS_RUNNING); + + /* + * Reset the number of write locks. + * This will be incremented by the + * new owner of the lock when it + * sees that it has the lock. + */ + _thread_fd_table[fd]->w_lockcount = 0; + } + } + } + + /* Unlock the file descriptor table entry: */ + _SPINUNLOCK(&_thread_fd_table[fd]->lock); + + /* + * Undefer and handle pending signals, yielding if + * necessary: + */ + _thread_kern_sig_undefer(); + } +} + +int +_thread_fd_lock(int fd, int lock_type, struct timespec * timeout) +{ + struct pthread *curthread = _get_curthread(); + int ret; + + /* + * Check that the file descriptor table is initialised for this + * entry: + */ + if ((ret = _thread_fd_table_init(fd)) == 0) { + /* Clear the interrupted flag: */ + curthread->interrupted = 0; + + /* + * Lock the file descriptor table entry to prevent + * other threads for clashing with the current + * thread's accesses: + */ + _SPINLOCK(&_thread_fd_table[fd]->lock); + + /* Check the file descriptor and lock types: */ + if (lock_type == FD_READ || lock_type == FD_RDWR) { + /* + * Wait for the file descriptor to be locked + * for read for the current thread: + */ + while ((_thread_fd_table[fd]->r_owner != curthread) && + (curthread->interrupted == 0)) { + /* + * Check if the file descriptor is locked by + * another thread: + */ + if (_thread_fd_table[fd]->r_owner != NULL) { + /* + * Another thread has locked the file + * descriptor for read, so join the + * queue of threads waiting for a + * read lock on this file descriptor: + */ + FDQ_INSERT(&_thread_fd_table[fd]->r_queue, curthread); + + /* + * Save the file descriptor details + * in the thread structure for the + * running thread: + */ + curthread->data.fd.fd = fd; + + /* Set the timeout: */ + _thread_kern_set_timeout(timeout); + + /* + * Unlock the file descriptor + * table entry: + */ + _SPINUNLOCK(&_thread_fd_table[fd]->lock); + + /* + * Schedule this thread to wait on + * the read lock. It will only be + * woken when it becomes the next in + * the queue and is granted access + * to the lock by the thread + * that is unlocking the file + * descriptor. + */ + _thread_kern_sched_state(PS_FDLR_WAIT, __FILE__, __LINE__); + + /* + * Lock the file descriptor + * table entry again: + */ + _SPINLOCK(&_thread_fd_table[fd]->lock); + + if (curthread->interrupted != 0) { + FDQ_REMOVE(&_thread_fd_table[fd]->r_queue, + curthread); + } + } else { + /* + * The running thread now owns the + * read lock on this file descriptor: + */ + _thread_fd_table[fd]->r_owner = curthread; + + /* + * Reset the number of read locks for + * this file descriptor: + */ + _thread_fd_table[fd]->r_lockcount = 0; + } + } + + if (_thread_fd_table[fd]->r_owner == curthread) + /* Increment the read lock count: */ + _thread_fd_table[fd]->r_lockcount++; + } + + /* Check the file descriptor and lock types: */ + if (curthread->interrupted == 0 && + (lock_type == FD_WRITE || lock_type == FD_RDWR)) { + /* + * Wait for the file descriptor to be locked + * for write for the current thread: + */ + while ((_thread_fd_table[fd]->w_owner != curthread) && + (curthread->interrupted == 0)) { + /* + * Check if the file descriptor is locked by + * another thread: + */ + if (_thread_fd_table[fd]->w_owner != NULL) { + /* + * Another thread has locked the file + * descriptor for write, so join the + * queue of threads waiting for a + * write lock on this file + * descriptor: + */ + FDQ_INSERT(&_thread_fd_table[fd]->w_queue, curthread); + + /* + * Save the file descriptor details + * in the thread structure for the + * running thread: + */ + curthread->data.fd.fd = fd; + + /* Set the timeout: */ + _thread_kern_set_timeout(timeout); + + /* + * Unlock the file descriptor + * table entry: + */ + _SPINUNLOCK(&_thread_fd_table[fd]->lock); + + /* + * Schedule this thread to wait on + * the write lock. It will only be + * woken when it becomes the next in + * the queue and is granted access to + * the lock by the thread that is + * unlocking the file descriptor. + */ + _thread_kern_sched_state(PS_FDLW_WAIT, __FILE__, __LINE__); + + /* + * Lock the file descriptor + * table entry again: + */ + _SPINLOCK(&_thread_fd_table[fd]->lock); + + if (curthread->interrupted != 0) { + FDQ_REMOVE(&_thread_fd_table[fd]->w_queue, + curthread); + } + } else { + /* + * The running thread now owns the + * write lock on this file + * descriptor: + */ + _thread_fd_table[fd]->w_owner = curthread; + + /* + * Reset the number of write locks + * for this file descriptor: + */ + _thread_fd_table[fd]->w_lockcount = 0; + } + } + + if (_thread_fd_table[fd]->w_owner == curthread) + /* Increment the write lock count: */ + _thread_fd_table[fd]->w_lockcount++; + } + + /* Unlock the file descriptor table entry: */ + _SPINUNLOCK(&_thread_fd_table[fd]->lock); + + if (curthread->interrupted != 0) { + ret = -1; + errno = EINTR; + if (curthread->continuation != NULL) + curthread->continuation((void *)curthread); + } + } + + /* Return the completion status: */ + return (ret); +} + +void +_thread_fd_unlock_debug(int fd, int lock_type, char *fname, int lineno) +{ + struct pthread *curthread = _get_curthread(); + int ret; + + /* + * Check that the file descriptor table is initialised for this + * entry: + */ + if ((ret = _thread_fd_table_init(fd)) == 0) { + /* + * Defer signals to protect the scheduling queues from + * access by the signal handler: + */ + _thread_kern_sig_defer(); + + /* + * Lock the file descriptor table entry to prevent + * other threads for clashing with the current + * thread's accesses: + */ + _spinlock_debug(&_thread_fd_table[fd]->lock, fname, lineno); + + /* Check if the running thread owns the read lock: */ + if (_thread_fd_table[fd]->r_owner == curthread) { + /* Check the file descriptor and lock types: */ + if (lock_type == FD_READ || lock_type == FD_RDWR) { + /* + * Decrement the read lock count for the + * running thread: + */ + _thread_fd_table[fd]->r_lockcount--; + + /* + * Check if the running thread still has read + * locks on this file descriptor: + */ + if (_thread_fd_table[fd]->r_lockcount != 0) { + } + /* + * Get the next thread in the queue for a + * read lock on this file descriptor: + */ + else if ((_thread_fd_table[fd]->r_owner = fd_next_reader(fd)) == NULL) { + } else { + /* Remove this thread from the queue: */ + FDQ_REMOVE(&_thread_fd_table[fd]->r_queue, + _thread_fd_table[fd]->r_owner); + + /* + * Set the state of the new owner of + * the thread to running: + */ + PTHREAD_NEW_STATE(_thread_fd_table[fd]->r_owner,PS_RUNNING); + + /* + * Reset the number of read locks. + * This will be incremented by the + * new owner of the lock when it sees + * that it has the lock. + */ + _thread_fd_table[fd]->r_lockcount = 0; + } + } + } + /* Check if the running thread owns the write lock: */ + if (_thread_fd_table[fd]->w_owner == curthread) { + /* Check the file descriptor and lock types: */ + if (lock_type == FD_WRITE || lock_type == FD_RDWR) { + /* + * Decrement the write lock count for the + * running thread: + */ + _thread_fd_table[fd]->w_lockcount--; + + /* + * Check if the running thread still has + * write locks on this file descriptor: + */ + if (_thread_fd_table[fd]->w_lockcount != 0) { + } + /* + * Get the next thread in the queue for a + * write lock on this file descriptor: + */ + else if ((_thread_fd_table[fd]->w_owner = fd_next_writer(fd)) == NULL) { + } else { + /* Remove this thread from the queue: */ + FDQ_REMOVE(&_thread_fd_table[fd]->w_queue, + _thread_fd_table[fd]->w_owner); + + /* + * Set the state of the new owner of + * the thread to running: + */ + PTHREAD_NEW_STATE(_thread_fd_table[fd]->w_owner,PS_RUNNING); + + /* + * Reset the number of write locks. + * This will be incremented by the + * new owner of the lock when it + * sees that it has the lock. + */ + _thread_fd_table[fd]->w_lockcount = 0; + } + } + } + + /* Unlock the file descriptor table entry: */ + _SPINUNLOCK(&_thread_fd_table[fd]->lock); + + /* + * Undefer and handle pending signals, yielding if + * necessary. + */ + _thread_kern_sig_undefer(); + } +} + +int +_thread_fd_lock_debug(int fd, int lock_type, struct timespec * timeout, + char *fname, int lineno) +{ + struct pthread *curthread = _get_curthread(); + int ret; + + /* + * Check that the file descriptor table is initialised for this + * entry: + */ + if ((ret = _thread_fd_table_init(fd)) == 0) { + /* Clear the interrupted flag: */ + curthread->interrupted = 0; + + /* + * Lock the file descriptor table entry to prevent + * other threads for clashing with the current + * thread's accesses: + */ + _spinlock_debug(&_thread_fd_table[fd]->lock, fname, lineno); + + /* Check the file descriptor and lock types: */ + if (lock_type == FD_READ || lock_type == FD_RDWR) { + /* + * Wait for the file descriptor to be locked + * for read for the current thread: + */ + while ((_thread_fd_table[fd]->r_owner != curthread) && + (curthread->interrupted == 0)) { + /* + * Check if the file descriptor is locked by + * another thread: + */ + if (_thread_fd_table[fd]->r_owner != NULL) { + /* + * Another thread has locked the file + * descriptor for read, so join the + * queue of threads waiting for a + * read lock on this file descriptor: + */ + FDQ_INSERT(&_thread_fd_table[fd]->r_queue, curthread); + + /* + * Save the file descriptor details + * in the thread structure for the + * running thread: + */ + curthread->data.fd.fd = fd; + curthread->data.fd.branch = lineno; + curthread->data.fd.fname = fname; + + /* Set the timeout: */ + _thread_kern_set_timeout(timeout); + + /* + * Unlock the file descriptor + * table entry: + */ + _SPINUNLOCK(&_thread_fd_table[fd]->lock); + + /* + * Schedule this thread to wait on + * the read lock. It will only be + * woken when it becomes the next in + * the queue and is granted access + * to the lock by the thread + * that is unlocking the file + * descriptor. + */ + _thread_kern_sched_state(PS_FDLR_WAIT, __FILE__, __LINE__); + + /* + * Lock the file descriptor + * table entry again: + */ + _SPINLOCK(&_thread_fd_table[fd]->lock); + + if (curthread->interrupted != 0) { + FDQ_REMOVE(&_thread_fd_table[fd]->r_queue, + curthread); + } + } else { + /* + * The running thread now owns the + * read lock on this file descriptor: + */ + _thread_fd_table[fd]->r_owner = curthread; + + /* + * Reset the number of read locks for + * this file descriptor: + */ + _thread_fd_table[fd]->r_lockcount = 0; + + /* + * Save the source file details for + * debugging: + */ + _thread_fd_table[fd]->r_fname = fname; + _thread_fd_table[fd]->r_lineno = lineno; + } + } + + if (_thread_fd_table[fd]->r_owner == curthread) + /* Increment the read lock count: */ + _thread_fd_table[fd]->r_lockcount++; + } + + /* Check the file descriptor and lock types: */ + if (curthread->interrupted == 0 && + (lock_type == FD_WRITE || lock_type == FD_RDWR)) { + /* + * Wait for the file descriptor to be locked + * for write for the current thread: + */ + while ((_thread_fd_table[fd]->w_owner != curthread) && + (curthread->interrupted == 0)) { + /* + * Check if the file descriptor is locked by + * another thread: + */ + if (_thread_fd_table[fd]->w_owner != NULL) { + /* + * Another thread has locked the file + * descriptor for write, so join the + * queue of threads waiting for a + * write lock on this file + * descriptor: + */ + FDQ_INSERT(&_thread_fd_table[fd]->w_queue, curthread); + + /* + * Save the file descriptor details + * in the thread structure for the + * running thread: + */ + curthread->data.fd.fd = fd; + curthread->data.fd.branch = lineno; + curthread->data.fd.fname = fname; + + /* Set the timeout: */ + _thread_kern_set_timeout(timeout); + + /* + * Unlock the file descriptor + * table entry: + */ + _SPINUNLOCK(&_thread_fd_table[fd]->lock); + + /* + * Schedule this thread to wait on + * the write lock. It will only be + * woken when it becomes the next in + * the queue and is granted access to + * the lock by the thread that is + * unlocking the file descriptor. + */ + _thread_kern_sched_state(PS_FDLW_WAIT, __FILE__, __LINE__); + + /* + * Lock the file descriptor + * table entry again: + */ + _SPINLOCK(&_thread_fd_table[fd]->lock); + + if (curthread->interrupted != 0) { + FDQ_REMOVE(&_thread_fd_table[fd]->w_queue, + curthread); + } + } else { + /* + * The running thread now owns the + * write lock on this file + * descriptor: + */ + _thread_fd_table[fd]->w_owner = curthread; + + /* + * Reset the number of write locks + * for this file descriptor: + */ + _thread_fd_table[fd]->w_lockcount = 0; + + /* + * Save the source file details for + * debugging: + */ + _thread_fd_table[fd]->w_fname = fname; + _thread_fd_table[fd]->w_lineno = lineno; + } + } + + if (_thread_fd_table[fd]->w_owner == curthread) + /* Increment the write lock count: */ + _thread_fd_table[fd]->w_lockcount++; + } + + /* Unlock the file descriptor table entry: */ + _SPINUNLOCK(&_thread_fd_table[fd]->lock); + + if (curthread->interrupted != 0) { + ret = -1; + errno = EINTR; + if (curthread->continuation != NULL) + curthread->continuation((void *)curthread); + } + } + + /* Return the completion status: */ + return (ret); +} + +void +_thread_fd_unlock_owned(pthread_t pthread) +{ + int fd; + + for (fd = 0; fd < _thread_dtablesize; fd++) { + if ((_thread_fd_table[fd] != NULL) && + ((_thread_fd_table[fd]->r_owner == pthread) || + (_thread_fd_table[fd]->w_owner == pthread))) { + /* + * Defer signals to protect the scheduling queues + * from access by the signal handler: + */ + _thread_kern_sig_defer(); + + /* + * Lock the file descriptor table entry to prevent + * other threads for clashing with the current + * thread's accesses: + */ + _SPINLOCK(&_thread_fd_table[fd]->lock); + + /* Check if the thread owns the read lock: */ + if (_thread_fd_table[fd]->r_owner == pthread) { + /* Clear the read lock count: */ + _thread_fd_table[fd]->r_lockcount = 0; + + /* + * Get the next thread in the queue for a + * read lock on this file descriptor: + */ + if ((_thread_fd_table[fd]->r_owner = fd_next_reader(fd)) != NULL) { + /* Remove this thread from the queue: */ + FDQ_REMOVE(&_thread_fd_table[fd]->r_queue, + _thread_fd_table[fd]->r_owner); + + /* + * Set the state of the new owner of + * the thread to running: + */ + PTHREAD_NEW_STATE(_thread_fd_table[fd]->r_owner,PS_RUNNING); + } + } + + /* Check if the thread owns the write lock: */ + if (_thread_fd_table[fd]->w_owner == pthread) { + /* Clear the write lock count: */ + _thread_fd_table[fd]->w_lockcount = 0; + + /* + * Get the next thread in the queue for a + * write lock on this file descriptor: + */ + if ((_thread_fd_table[fd]->w_owner = fd_next_writer(fd)) != NULL) { + /* Remove this thread from the queue: */ + FDQ_REMOVE(&_thread_fd_table[fd]->w_queue, + _thread_fd_table[fd]->w_owner); + + /* + * Set the state of the new owner of + * the thread to running: + */ + PTHREAD_NEW_STATE(_thread_fd_table[fd]->w_owner,PS_RUNNING); + + } + } + + /* Unlock the file descriptor table entry: */ + _SPINUNLOCK(&_thread_fd_table[fd]->lock); + + /* + * Undefer and handle pending signals, yielding if + * necessary. + */ + _thread_kern_sig_undefer(); + } + } +} + +void +_fd_lock_backout(pthread_t pthread) +{ + int fd; + + /* + * Defer signals to protect the scheduling queues + * from access by the signal handler: + */ + _thread_kern_sig_defer(); + + switch (pthread->state) { + + case PS_FDLR_WAIT: + fd = pthread->data.fd.fd; + + /* + * Lock the file descriptor table entry to prevent + * other threads for clashing with the current + * thread's accesses: + */ + _SPINLOCK(&_thread_fd_table[fd]->lock); + + /* Remove the thread from the waiting queue: */ + FDQ_REMOVE(&_thread_fd_table[fd]->r_queue, pthread); + break; + + case PS_FDLW_WAIT: + fd = pthread->data.fd.fd; + + /* + * Lock the file descriptor table entry to prevent + * other threads from clashing with the current + * thread's accesses: + */ + _SPINLOCK(&_thread_fd_table[fd]->lock); + + /* Remove the thread from the waiting queue: */ + FDQ_REMOVE(&_thread_fd_table[fd]->w_queue, pthread); + break; + + default: + break; + } + + /* + * Undefer and handle pending signals, yielding if + * necessary. + */ + _thread_kern_sig_undefer(); +} + +static inline pthread_t +fd_next_reader(int fd) +{ + pthread_t pthread; + + while (((pthread = TAILQ_FIRST(&_thread_fd_table[fd]->r_queue)) != NULL) && + (pthread->interrupted != 0)) { + /* + * This thread has either been interrupted by a signal or + * it has been canceled. Remove it from the queue. + */ + FDQ_REMOVE(&_thread_fd_table[fd]->r_queue, pthread); + } + + return (pthread); +} + +static inline pthread_t +fd_next_writer(int fd) +{ + pthread_t pthread; + + while (((pthread = TAILQ_FIRST(&_thread_fd_table[fd]->w_queue)) != NULL) && + (pthread->interrupted != 0)) { + /* + * This thread has either been interrupted by a signal or + * it has been canceled. Remove it from the queue. + */ + FDQ_REMOVE(&_thread_fd_table[fd]->w_queue, pthread); + } + + return (pthread); +} + +#else + +void +_thread_fd_unlock(int fd, int lock_type) +{ +} + +int +_thread_fd_lock(int fd, int lock_type, struct timespec * timeout) +{ + /* + * Insure that the file descriptor table is initialized for this + * entry: + */ + return (_thread_fd_table_init(fd)); +} + +void +_thread_fd_unlock_debug(int fd, int lock_type, char *fname, int lineno) +{ +} + +int +_thread_fd_lock_debug(int fd, int lock_type, struct timespec * timeout, + char *fname, int lineno) +{ + /* + * Insure that the file descriptor table is initialized for this + * entry: + */ + return (_thread_fd_table_init(fd)); +} + +void +_thread_fd_unlock_owned(pthread_t pthread) +{ +} + +void +_fd_lock_backout(pthread_t pthread) +{ +} + +#endif diff --git a/lib/libc_r/uthread/uthread_file.c b/lib/libc_r/uthread/uthread_file.c new file mode 100644 index 0000000..cbedbc7 --- /dev/null +++ b/lib/libc_r/uthread/uthread_file.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>. + * Copyright (c) 2001 Daniel Eischen <deischen@FreeBSD.org> + * 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 AUTHOR 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. + * + * $FreeBSD$ + * + * POSIX stdio FILE locking functions. These assume that the locking + * is only required at FILE structure level, not at file descriptor + * level too. + * + */ +#include <stdio.h> +#include <pthread.h> +#include "pthread_private.h" + +extern void _flockfile(FILE *); + +void +_flockfile_debug(FILE *fp, char *fname, int lineno) +{ + pthread_t curthread = _pthread_self(); + + curthread->lineno = lineno; + curthread->fname = fname; + _flockfile(fp); +} diff --git a/lib/libc_r/uthread/uthread_find_thread.c b/lib/libc_r/uthread/uthread_find_thread.c new file mode 100644 index 0000000..e6e9294 --- /dev/null +++ b/lib/libc_r/uthread/uthread_find_thread.c @@ -0,0 +1,66 @@ +/* + * Copyright (c) 1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +/* Find a thread in the linked list of active threads: */ +int +_find_thread(pthread_t pthread) +{ + pthread_t pthread1; + + /* Check if the caller has specified an invalid thread: */ + if (pthread == NULL || pthread->magic != PTHREAD_MAGIC) + /* Invalid thread: */ + return(EINVAL); + + /* + * Defer signals to protect the thread list from access + * by the signal handler: + */ + _thread_kern_sig_defer(); + + /* Search for the specified thread: */ + TAILQ_FOREACH(pthread1, &_thread_list, tle) { + if (pthread == pthread1) + break; + } + + /* Undefer and handle pending signals, yielding if necessary: */ + _thread_kern_sig_undefer(); + + /* Return zero if the thread exists: */ + return ((pthread1 != NULL) ? 0:ESRCH); +} diff --git a/lib/libc_r/uthread/uthread_flock.c b/lib/libc_r/uthread/uthread_flock.c new file mode 100644 index 0000000..03312ff --- /dev/null +++ b/lib/libc_r/uthread/uthread_flock.c @@ -0,0 +1,50 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <sys/file.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_flock, flock); + +int +_flock(int fd, int operation) +{ + int ret; + + if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) { + ret = __sys_flock(fd, operation); + _FD_UNLOCK(fd, FD_RDWR); + } + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_fork.c b/lib/libc_r/uthread/uthread_fork.c new file mode 100644 index 0000000..dd6d3ff --- /dev/null +++ b/lib/libc_r/uthread/uthread_fork.c @@ -0,0 +1,243 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <sys/param.h> +#include <errno.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <fcntl.h> +#include <pthread.h> +#include "pthread_private.h" + +static void free_thread_resources(struct pthread *thread); + +__weak_reference(_fork, fork); + +pid_t +_fork(void) +{ + struct pthread *curthread = _get_curthread(); + int i, flags, use_deadlist = 0; + pid_t ret; + pthread_t pthread; + pthread_t pthread_save; + + /* + * Defer signals to protect the scheduling queues from access + * by the signal handler: + */ + _thread_kern_sig_defer(); + + /* Fork a new process: */ + if ((ret = __sys_fork()) != 0) { + /* Parent process or error. Nothing to do here. */ + } else { + /* Close the pthread kernel pipe: */ + __sys_close(_thread_kern_pipe[0]); + __sys_close(_thread_kern_pipe[1]); + + /* Reset signals pending for the running thread: */ + sigemptyset(&curthread->sigpend); + + /* + * Create a pipe that is written to by the signal handler to + * prevent signals being missed in calls to + * __sys_select: + */ + if (__sys_pipe(_thread_kern_pipe) != 0) { + /* Cannot create pipe, so abort: */ + PANIC("Cannot create pthread kernel pipe for forked process"); + } + /* Get the flags for the read pipe: */ + else if ((flags = __sys_fcntl(_thread_kern_pipe[0], F_GETFL, NULL)) == -1) { + /* Abort this application: */ + abort(); + } + /* Make the read pipe non-blocking: */ + else if (__sys_fcntl(_thread_kern_pipe[0], F_SETFL, flags | O_NONBLOCK) == -1) { + /* Abort this application: */ + abort(); + } + /* Get the flags for the write pipe: */ + else if ((flags = __sys_fcntl(_thread_kern_pipe[1], F_GETFL, NULL)) == -1) { + /* Abort this application: */ + abort(); + } + /* Make the write pipe non-blocking: */ + else if (__sys_fcntl(_thread_kern_pipe[1], F_SETFL, flags | O_NONBLOCK) == -1) { + /* Abort this application: */ + abort(); + } + /* Reinitialize the GC mutex: */ + else if (_mutex_reinit(&_gc_mutex) != 0) { + /* Abort this application: */ + PANIC("Cannot initialize GC mutex for forked process"); + } + /* Reinitialize the GC condition variable: */ + else if (_cond_reinit(&_gc_cond) != 0) { + /* Abort this application: */ + PANIC("Cannot initialize GC condvar for forked process"); + } + /* Initialize the ready queue: */ + else if (_pq_init(&_readyq) != 0) { + /* Abort this application: */ + PANIC("Cannot initialize priority ready queue."); + } else { + /* + * Enter a loop to remove all threads other than + * the running thread from the thread list: + */ + if ((pthread = TAILQ_FIRST(&_thread_list)) == NULL) { + pthread = TAILQ_FIRST(&_dead_list); + use_deadlist = 1; + } + while (pthread != NULL) { + /* Save the thread to be freed: */ + pthread_save = pthread; + + /* + * Advance to the next thread before + * destroying the current thread: + */ + if (use_deadlist != 0) + pthread = TAILQ_NEXT(pthread, dle); + else + pthread = TAILQ_NEXT(pthread, tle); + + /* Make sure this isn't the running thread: */ + if (pthread_save != curthread) { + /* + * Remove this thread from the + * appropriate list: + */ + if (use_deadlist != 0) + TAILQ_REMOVE(&_thread_list, + pthread_save, dle); + else + TAILQ_REMOVE(&_thread_list, + pthread_save, tle); + + free_thread_resources(pthread_save); + } + + /* + * Switch to the deadlist when the active + * thread list has been consumed. This can't + * be at the top of the loop because it is + * used to determine to which list the thread + * belongs (when it is removed from the list). + */ + if (pthread == NULL) { + pthread = TAILQ_FIRST(&_dead_list); + use_deadlist = 1; + } + } + + /* Treat the current thread as the initial thread: */ + _thread_initial = curthread; + + /* Re-init the dead thread list: */ + TAILQ_INIT(&_dead_list); + + /* Re-init the waiting and work queues. */ + TAILQ_INIT(&_waitingq); + TAILQ_INIT(&_workq); + + /* Re-init the threads mutex queue: */ + TAILQ_INIT(&curthread->mutexq); + + /* No spinlocks yet: */ + _spinblock_count = 0; + + /* Don't queue signals yet: */ + _queue_signals = 0; + + /* Initialize the scheduling switch hook routine: */ + _sched_switch_hook = NULL; + + /* Clear out any locks in the file descriptor table: */ + for (i = 0; i < _thread_dtablesize; i++) { + if (_thread_fd_table[i] != NULL) { + /* Initialise the file locks: */ + memset(&_thread_fd_table[i]->lock, 0, + sizeof(_thread_fd_table[i]->lock)); + _thread_fd_table[i]->r_owner = NULL; + _thread_fd_table[i]->w_owner = NULL; + _thread_fd_table[i]->r_fname = NULL; + _thread_fd_table[i]->w_fname = NULL; + _thread_fd_table[i]->r_lineno = 0;; + _thread_fd_table[i]->w_lineno = 0;; + _thread_fd_table[i]->r_lockcount = 0;; + _thread_fd_table[i]->w_lockcount = 0;; + + /* Initialise the read/write queues: */ + TAILQ_INIT(&_thread_fd_table[i]->r_queue); + TAILQ_INIT(&_thread_fd_table[i]->w_queue); + } + } + } + } + + /* + * Undefer and handle pending signals, yielding if necessary: + */ + _thread_kern_sig_undefer(); + + /* Return the process ID: */ + return (ret); +} + +static void +free_thread_resources(struct pthread *thread) +{ + + /* Check to see if the threads library allocated the stack. */ + if ((thread->attr.stackaddr_attr == NULL) && (thread->stack != NULL)) { + /* + * Since this is being called from fork, we are currently single + * threaded so there is no need to protect the call to + * _thread_stack_free() with _gc_mutex. + */ + _thread_stack_free(thread->stack, thread->attr.stacksize_attr, + thread->attr.guardsize_attr); + } + + if (thread->specific != NULL) + free(thread->specific); + + if (thread->poll_data.fds != NULL) + free(thread->poll_data.fds); + + free(thread); +} diff --git a/lib/libc_r/uthread/uthread_fpathconf.c b/lib/libc_r/uthread/uthread_fpathconf.c new file mode 100644 index 0000000..97e1d65 --- /dev/null +++ b/lib/libc_r/uthread/uthread_fpathconf.c @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2000 Maxim Sobolev <sobomax@FreeBSD.org> + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <unistd.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_fpathconf, fpathconf); + +long +_fpathconf(int fd, int name) +{ + long ret; + + if ((ret = _FD_LOCK(fd, FD_READ, NULL)) == 0) { + ret = __sys_fpathconf(fd, name); + _FD_UNLOCK(fd, FD_READ); + } + return ret; +} + diff --git a/lib/libc_r/uthread/uthread_fstat.c b/lib/libc_r/uthread/uthread_fstat.c new file mode 100644 index 0000000..0aa49d1 --- /dev/null +++ b/lib/libc_r/uthread/uthread_fstat.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <signal.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/mount.h> +#include <sys/stat.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_fstat, fstat); + +int +_fstat(int fd, struct stat * buf) +{ + int ret; + + /* Lock the file descriptor for read: */ + if ((ret = _FD_LOCK(fd, FD_READ, NULL)) == 0) { + /* Get the file status: */ + ret = __sys_fstat(fd, buf); + /* Unlock the file descriptor: */ + _FD_UNLOCK(fd, FD_READ); + } + return (ret); +} + diff --git a/lib/libc_r/uthread/uthread_fstatfs.c b/lib/libc_r/uthread/uthread_fstatfs.c new file mode 100644 index 0000000..80a8fd5 --- /dev/null +++ b/lib/libc_r/uthread/uthread_fstatfs.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <signal.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/param.h> +#include <sys/mount.h> +#include <sys/stat.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_fstatfs, fstatfs); + +int +_fstatfs(int fd, struct statfs * buf) +{ + int ret; + + /* Lock the file descriptor for read: */ + if ((ret = _FD_LOCK(fd, FD_READ, NULL)) == 0) { + /* Get the file system status: */ + ret = __sys_fstatfs(fd, buf); + /* Unlock the file descriptor: */ + _FD_UNLOCK(fd, FD_READ); + } + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_fsync.c b/lib/libc_r/uthread/uthread_fsync.c new file mode 100644 index 0000000..b8b9f3c --- /dev/null +++ b/lib/libc_r/uthread/uthread_fsync.c @@ -0,0 +1,62 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <unistd.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(__fsync, fsync); + +int +_fsync(int fd) +{ + int ret; + + if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) { + ret = __sys_fsync(fd); + _FD_UNLOCK(fd, FD_RDWR); + } + return (ret); +} + +int +__fsync(int fd) +{ + int ret; + + _thread_enter_cancellation_point(); + ret = _fsync(fd); + _thread_leave_cancellation_point(); + + return ret; +} diff --git a/lib/libc_r/uthread/uthread_gc.c b/lib/libc_r/uthread/uthread_gc.c new file mode 100644 index 0000000..9c93028 --- /dev/null +++ b/lib/libc_r/uthread/uthread_gc.c @@ -0,0 +1,219 @@ +/* + * Copyright (c) 1998 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 AUTHOR 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. + * + * $FreeBSD$ + * + * Garbage collector thread. Frees memory allocated for dead threads. + * + */ +#include <sys/param.h> +#include <errno.h> +#include <time.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <pthread.h> +#include "pthread_private.h" + +pthread_addr_t +_thread_gc(pthread_addr_t arg) +{ + struct pthread *curthread = _get_curthread(); + int f_debug; + int f_done = 0; + int ret; + sigset_t mask; + pthread_t pthread; + pthread_t pthread_cln; + struct timespec abstime; + void *p_stack; + + /* Block all signals */ + sigfillset(&mask); + pthread_sigmask(SIG_BLOCK, &mask, NULL); + + /* Mark this thread as a library thread (not a user thread). */ + curthread->flags |= PTHREAD_FLAGS_PRIVATE; + + /* Set a debug flag based on an environment variable. */ + f_debug = (getenv("LIBC_R_DEBUG") != NULL); + + /* Set the name of this thread. */ + pthread_set_name_np(curthread,"GC"); + + while (!f_done) { + /* Check if debugging this application. */ + if (f_debug) + /* Dump thread info to file. */ + _thread_dump_info(); + + /* + * Defer signals to protect the scheduling queues from + * access by the signal handler: + */ + _thread_kern_sig_defer(); + + /* Check if this is the last running thread: */ + if (TAILQ_FIRST(&_thread_list) == curthread && + TAILQ_NEXT(curthread, tle) == NULL) + /* + * This is the last thread, so it can exit + * now. + */ + f_done = 1; + + /* + * Undefer and handle pending signals, yielding if + * necessary: + */ + _thread_kern_sig_undefer(); + + /* No stack of thread structure to free yet: */ + p_stack = NULL; + pthread_cln = NULL; + + /* + * Lock the garbage collector mutex which ensures that + * this thread sees another thread exit: + */ + if (pthread_mutex_lock(&_gc_mutex) != 0) + PANIC("Cannot lock gc mutex"); + + /* + * Enter a loop to search for the first dead thread that + * has memory to free. + */ + for (pthread = TAILQ_FIRST(&_dead_list); + p_stack == NULL && pthread_cln == NULL && pthread != NULL; + pthread = TAILQ_NEXT(pthread, dle)) { + /* Check if the initial thread: */ + if (pthread == _thread_initial) { + /* Don't destroy the initial thread. */ + } + /* + * Check if this thread has detached: + */ + else if ((pthread->attr.flags & + PTHREAD_DETACHED) != 0) { + /* Remove this thread from the dead list: */ + TAILQ_REMOVE(&_dead_list, pthread, dle); + + /* + * Check if the stack was not specified by + * the caller to pthread_create() and has not + * been destroyed yet: + */ + if (pthread->attr.stackaddr_attr == NULL && + pthread->stack != NULL) { + _thread_stack_free(pthread->stack, + pthread->attr.stacksize_attr, + pthread->attr.guardsize_attr); + } + + /* + * Point to the thread structure that must + * be freed outside the locks: + */ + pthread_cln = pthread; + + } else { + /* + * This thread has not detached, so do + * not destroy it. + * + * Check if the stack was not specified by + * the caller to pthread_create() and has not + * been destroyed yet: + */ + if (pthread->attr.stackaddr_attr == NULL && + pthread->stack != NULL) { + _thread_stack_free(pthread->stack, + pthread->attr.stacksize_attr, + pthread->attr.guardsize_attr); + + /* + * NULL the stack pointer now that the + * memory has been freed: + */ + pthread->stack = NULL; + } + } + } + + /* + * Check if this is not the last thread and there is no + * memory to free this time around. + */ + if (!f_done && p_stack == NULL && pthread_cln == NULL) { + /* Get the current time. */ + if (clock_gettime(CLOCK_REALTIME,&abstime) != 0) + PANIC("gc cannot get time"); + + /* + * Do a backup poll in 10 seconds if no threads + * die before then. + */ + abstime.tv_sec += 10; + + /* + * Wait for a signal from a dying thread or a + * timeout (for a backup poll). + */ + if ((ret = pthread_cond_timedwait(&_gc_cond, + &_gc_mutex, &abstime)) != 0 && ret != ETIMEDOUT) + PANIC("gc cannot wait for a signal"); + } + + /* Unlock the garbage collector mutex: */ + if (pthread_mutex_unlock(&_gc_mutex) != 0) + PANIC("Cannot unlock gc mutex"); + + /* + * If there is memory to free, do it now. The call to + * free() might block, so this must be done outside the + * locks. + */ + if (p_stack != NULL) + free(p_stack); + if (pthread_cln != NULL) { + if (pthread_cln->name != NULL) { + /* Free the thread name string. */ + free(pthread_cln->name); + } + /* + * Free the memory allocated for the thread + * structure. + */ + free(pthread_cln); + } + } + return (NULL); +} diff --git a/lib/libc_r/uthread/uthread_getdirentries.c b/lib/libc_r/uthread/uthread_getdirentries.c new file mode 100644 index 0000000..b633c08 --- /dev/null +++ b/lib/libc_r/uthread/uthread_getdirentries.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <sys/types.h> +#include <dirent.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_getdirentries, getdirentries); + +int +_getdirentries(int fd, char *buf, int nbytes, long *basep) +{ + int ret; + + if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) { + ret = __sys_getdirentries(fd, buf, nbytes, basep); + _FD_UNLOCK(fd, FD_RDWR); + } + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_getpeername.c b/lib/libc_r/uthread/uthread_getpeername.c new file mode 100644 index 0000000..8ff8b43 --- /dev/null +++ b/lib/libc_r/uthread/uthread_getpeername.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <sys/types.h> +#include <sys/socket.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_getpeername, getpeername); + +int +_getpeername(int fd, struct sockaddr * peer, socklen_t *paddrlen) +{ + int ret; + + if ((ret = _FD_LOCK(fd, FD_READ, NULL)) == 0) { + ret = __sys_getpeername(fd, peer, paddrlen); + _FD_UNLOCK(fd, FD_READ); + } + return ret; +} + diff --git a/lib/libc_r/uthread/uthread_getprio.c b/lib/libc_r/uthread/uthread_getprio.c new file mode 100644 index 0000000..a10c889 --- /dev/null +++ b/lib/libc_r/uthread/uthread_getprio.c @@ -0,0 +1,56 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_getprio, pthread_getprio); + +int +_pthread_getprio(pthread_t pthread) +{ + int policy, ret; + struct sched_param param; + + if ((ret = pthread_getschedparam(pthread, &policy, ¶m)) == 0) + ret = param.sched_priority; + else { + /* Invalid thread: */ + errno = ret; + ret = -1; + } + + /* Return the thread priority or an error status: */ + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_getschedparam.c b/lib/libc_r/uthread/uthread_getschedparam.c new file mode 100644 index 0000000..0d1ffe9 --- /dev/null +++ b/lib/libc_r/uthread/uthread_getschedparam.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * 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 Daniel Eischen. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_getschedparam, pthread_getschedparam); + +int +_pthread_getschedparam(pthread_t pthread, int *policy, + struct sched_param *param) +{ + int ret; + + if ((param == NULL) || (policy == NULL)) + /* Return an invalid argument error: */ + ret = EINVAL; + + /* Find the thread in the list of active threads: */ + else if ((ret = _find_thread(pthread)) == 0) { + /* Return the threads base priority and scheduling policy: */ + param->sched_priority = + PTHREAD_BASE_PRIORITY(pthread->base_priority); + *policy = pthread->attr.sched_policy; + } + + return(ret); +} diff --git a/lib/libc_r/uthread/uthread_getsockname.c b/lib/libc_r/uthread/uthread_getsockname.c new file mode 100644 index 0000000..745ba23 --- /dev/null +++ b/lib/libc_r/uthread/uthread_getsockname.c @@ -0,0 +1,51 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <sys/types.h> +#include <sys/socket.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_getsockname, getsockname); + +int +_getsockname(int s, struct sockaddr * name, socklen_t *namelen) +{ + int ret; + + if ((ret = _FD_LOCK(s, FD_READ, NULL)) == 0) { + ret = __sys_getsockname(s, name, namelen); + _FD_UNLOCK(s, FD_READ); + } + return ret; +} diff --git a/lib/libc_r/uthread/uthread_getsockopt.c b/lib/libc_r/uthread/uthread_getsockopt.c new file mode 100644 index 0000000..ad2d10e --- /dev/null +++ b/lib/libc_r/uthread/uthread_getsockopt.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <sys/types.h> +#include <sys/socket.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_getsockopt, getsockopt); + +int +_getsockopt(int fd, int level, int optname, void *optval, socklen_t + *optlen) +{ + int ret; + + if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) { + ret = __sys_getsockopt(fd, level, optname, optval, optlen); + _FD_UNLOCK(fd, FD_RDWR); + } + return ret; +} diff --git a/lib/libc_r/uthread/uthread_info.c b/lib/libc_r/uthread/uthread_info.c new file mode 100644 index 0000000..305a2b9 --- /dev/null +++ b/lib/libc_r/uthread/uthread_info.c @@ -0,0 +1,290 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <stdio.h> +#include <stdlib.h> +#include <fcntl.h> +#include <string.h> +#include <unistd.h> +#include <pthread.h> +#include <errno.h> +#include "pthread_private.h" + +#ifndef NELEMENTS +#define NELEMENTS(arr) (sizeof(arr) / sizeof(arr[0])) +#endif + +static void dump_thread(int fd, pthread_t pthread, int long_version); + +__weak_reference(_pthread_set_name_np, pthread_set_name_np); + +struct s_thread_info { + enum pthread_state state; + char *name; +}; + +/* Static variables: */ +static const struct s_thread_info thread_info[] = { + {PS_RUNNING , "Running"}, + {PS_SIGTHREAD , "Waiting on signal thread"}, + {PS_MUTEX_WAIT , "Waiting on a mutex"}, + {PS_COND_WAIT , "Waiting on a condition variable"}, + {PS_FDLR_WAIT , "Waiting for a file read lock"}, + {PS_FDLW_WAIT , "Waiting for a file write lock"}, + {PS_FDR_WAIT , "Waiting for read"}, + {PS_FDW_WAIT , "Waiting for write"}, + {PS_FILE_WAIT , "Waiting for FILE lock"}, + {PS_POLL_WAIT , "Waiting on poll"}, + {PS_SELECT_WAIT , "Waiting on select"}, + {PS_SLEEP_WAIT , "Sleeping"}, + {PS_WAIT_WAIT , "Waiting process"}, + {PS_SIGSUSPEND , "Suspended, waiting for a signal"}, + {PS_SIGWAIT , "Waiting for a signal"}, + {PS_SPINBLOCK , "Waiting for a spinlock"}, + {PS_JOIN , "Waiting to join"}, + {PS_SUSPENDED , "Suspended"}, + {PS_DEAD , "Dead"}, + {PS_DEADLOCK , "Deadlocked"}, + {PS_STATE_MAX , "Not a real state!"} +}; + +void +_thread_dump_info(void) +{ + char s[512]; + int fd; + int i; + pthread_t pthread; + char tmpfile[128]; + pq_list_t *pq_list; + + for (i = 0; i < 100000; i++) { + snprintf(tmpfile, sizeof(tmpfile), "/tmp/uthread.dump.%u.%i", + getpid(), i); + /* Open the dump file for append and create it if necessary: */ + if ((fd = __sys_open(tmpfile, O_RDWR | O_CREAT | O_EXCL, + 0666)) < 0) { + /* Can't open the dump file. */ + if (errno == EEXIST) + continue; + /* + * We only need to continue in case of + * EEXIT error. Most other error + * codes means that we will fail all + * the times. + */ + return; + } else { + break; + } + } + if (i==100000) { + /* all 100000 possibilities are in use :( */ + return; + } else { + /* Output a header for active threads: */ + strcpy(s, "\n\n=============\nACTIVE THREADS\n\n"); + __sys_write(fd, s, strlen(s)); + + /* Enter a loop to report each thread in the global list: */ + TAILQ_FOREACH(pthread, &_thread_list, tle) { + dump_thread(fd, pthread, /*long_verson*/ 1); + } + + /* Output a header for ready threads: */ + strcpy(s, "\n\n=============\nREADY THREADS\n\n"); + __sys_write(fd, s, strlen(s)); + + /* Enter a loop to report each thread in the ready queue: */ + TAILQ_FOREACH (pq_list, &_readyq.pq_queue, pl_link) { + TAILQ_FOREACH(pthread, &pq_list->pl_head, pqe) { + dump_thread(fd, pthread, /*long_version*/ 0); + } + } + + /* Output a header for waiting threads: */ + strcpy(s, "\n\n=============\nWAITING THREADS\n\n"); + __sys_write(fd, s, strlen(s)); + + /* Enter a loop to report each thread in the waiting queue: */ + TAILQ_FOREACH (pthread, &_waitingq, pqe) { + dump_thread(fd, pthread, /*long_version*/ 0); + } + + /* Output a header for threads in the work queue: */ + strcpy(s, "\n\n=============\nTHREADS IN WORKQ\n\n"); + __sys_write(fd, s, strlen(s)); + + /* Enter a loop to report each thread in the waiting queue: */ + TAILQ_FOREACH (pthread, &_workq, qe) { + dump_thread(fd, pthread, /*long_version*/ 0); + } + + /* Check if there are no dead threads: */ + if (TAILQ_FIRST(&_dead_list) == NULL) { + /* Output a record: */ + strcpy(s, "\n\nTHERE ARE NO DEAD THREADS\n"); + __sys_write(fd, s, strlen(s)); + } else { + /* Output a header for dead threads: */ + strcpy(s, "\n\nDEAD THREADS\n\n"); + __sys_write(fd, s, strlen(s)); + + /* + * Enter a loop to report each thread in the global + * dead thread list: + */ + TAILQ_FOREACH(pthread, &_dead_list, dle) { + dump_thread(fd, pthread, /*long_version*/ 0); + } + } + + /* Output a header for file descriptors: */ + snprintf(s, sizeof(s), "\n\n=============\nFILE DESCRIPTOR " + "TABLE (table size %d)\n\n", _thread_dtablesize); + __sys_write(fd, s, strlen(s)); + + /* Enter a loop to report file descriptor lock usage: */ + for (i = 0; i < _thread_dtablesize; i++) { + /* + * Check if memory is allocated for this file + * descriptor: + */ + if (_thread_fd_table[i] != NULL) { + /* Report the file descriptor lock status: */ + snprintf(s, sizeof(s), + "fd[%3d] read owner %p count %d [%s:%d]\n" + " write owner %p count %d [%s:%d]\n", + i, _thread_fd_table[i]->r_owner, + _thread_fd_table[i]->r_lockcount, + _thread_fd_table[i]->r_fname, + _thread_fd_table[i]->r_lineno, + _thread_fd_table[i]->w_owner, + _thread_fd_table[i]->w_lockcount, + _thread_fd_table[i]->w_fname, + _thread_fd_table[i]->w_lineno); + __sys_write(fd, s, strlen(s)); + } + } + + /* Close the dump file: */ + __sys_close(fd); + } +} + +static void +dump_thread(int fd, pthread_t pthread, int long_version) +{ + struct pthread *curthread = _get_curthread(); + char s[512]; + int i; + + /* Find the state: */ + for (i = 0; i < NELEMENTS(thread_info) - 1; i++) + if (thread_info[i].state == pthread->state) + break; + + /* Output a record for the thread: */ + snprintf(s, sizeof(s), + "--------------------\nThread %p (%s) prio %3d state %s [%s:%d]\n", + pthread, (pthread->name == NULL) ? "" : pthread->name, + pthread->active_priority, thread_info[i].name, pthread->fname, + pthread->lineno); + __sys_write(fd, s, strlen(s)); + + if (long_version != 0) { + /* Check if this is the running thread: */ + if (pthread == curthread) { + /* Output a record for the running thread: */ + strcpy(s, "This is the running thread\n"); + __sys_write(fd, s, strlen(s)); + } + /* Check if this is the initial thread: */ + if (pthread == _thread_initial) { + /* Output a record for the initial thread: */ + strcpy(s, "This is the initial thread\n"); + __sys_write(fd, s, strlen(s)); + } + /* Process according to thread state: */ + switch (pthread->state) { + /* File descriptor read lock wait: */ + case PS_FDLR_WAIT: + case PS_FDLW_WAIT: + case PS_FDR_WAIT: + case PS_FDW_WAIT: + /* Write the lock details: */ + snprintf(s, sizeof(s), "fd %d[%s:%d]", + pthread->data.fd.fd, + pthread->data.fd.fname, + pthread->data.fd.branch); + __sys_write(fd, s, strlen(s)); + snprintf(s, sizeof(s), "owner %pr/%pw\n", + _thread_fd_table[pthread->data.fd.fd]->r_owner, + _thread_fd_table[pthread->data.fd.fd]->w_owner); + __sys_write(fd, s, strlen(s)); + break; + case PS_SIGWAIT: + snprintf(s, sizeof(s), "sigmask (hi)"); + __sys_write(fd, s, strlen(s)); + for (i = _SIG_WORDS - 1; i >= 0; i--) { + snprintf(s, sizeof(s), "%08x\n", + pthread->sigmask.__bits[i]); + __sys_write(fd, s, strlen(s)); + } + snprintf(s, sizeof(s), "(lo)\n"); + __sys_write(fd, s, strlen(s)); + break; + /* + * Trap other states that are not explicitly + * coded to dump information: + */ + default: + /* Nothing to do here. */ + break; + } + } +} + +/* Set the thread name for debug: */ +void +_pthread_set_name_np(pthread_t thread, const char *name) +{ + /* Check if the caller has specified a valid thread: */ + if (thread != NULL && thread->magic == PTHREAD_MAGIC) { + if (thread->name != NULL) { + /* Free space for previous name. */ + free(thread->name); + } + thread->name = strdup(name); + } +} diff --git a/lib/libc_r/uthread/uthread_init.c b/lib/libc_r/uthread/uthread_init.c new file mode 100644 index 0000000..a3d62ae --- /dev/null +++ b/lib/libc_r/uthread/uthread_init.c @@ -0,0 +1,475 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +/* Allocate space for global thread variables here: */ +#define GLOBAL_PTHREAD_PRIVATE + +#include "namespace.h" +#include <sys/param.h> +#include <sys/types.h> +#include <machine/reg.h> + +#include <sys/ioctl.h> +#include <sys/mount.h> +#include <sys/uio.h> +#include <sys/socket.h> +#include <sys/event.h> +#include <sys/stat.h> +#include <sys/sysctl.h> +#include <sys/time.h> +#include <sys/ttycom.h> +#include <sys/user.h> +#include <sys/wait.h> +#include <sys/mman.h> +#include <dirent.h> +#include <errno.h> +#include <fcntl.h> +#include <paths.h> +#include <poll.h> +#include <pthread.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include "un-namespace.h" + +#include "pthread_private.h" + +/* + * All weak references used within libc should be in this table. + * This will is so that static libraries will work. + */ +static void *references[] = { + &_accept, + &_bind, + &_close, + &_connect, + &_dup, + &_dup2, + &_execve, + &_fcntl, + &_flock, + &_flockfile, + &_fstat, + &_fstatfs, + &_fsync, + &_funlockfile, + &_getdirentries, + &_getlogin, + &_getpeername, + &_getsockname, + &_getsockopt, + &_ioctl, + &_kevent, + &_listen, + &_nanosleep, + &_open, + &_pthread_getspecific, + &_pthread_key_create, + &_pthread_key_delete, + &_pthread_mutex_destroy, + &_pthread_mutex_init, + &_pthread_mutex_lock, + &_pthread_mutex_trylock, + &_pthread_mutex_unlock, + &_pthread_mutexattr_init, + &_pthread_mutexattr_destroy, + &_pthread_mutexattr_settype, + &_pthread_once, + &_pthread_setspecific, + &_read, + &_readv, + &_recvfrom, + &_recvmsg, + &_select, + &_sendmsg, + &_sendto, + &_setsockopt, + &_sigaction, + &_sigprocmask, + &_sigsuspend, + &_socket, + &_socketpair, + &_wait4, + &_write, + &_writev +}; + +/* + * These are needed when linking statically. All references within + * libgcc (and in the future libc) to these routines are weak, but + * if they are not (strongly) referenced by the application or other + * libraries, then the actual functions will not be loaded. + */ +static void *libgcc_references[] = { + &_pthread_once, + &_pthread_key_create, + &_pthread_key_delete, + &_pthread_getspecific, + &_pthread_setspecific, + &_pthread_mutex_init, + &_pthread_mutex_destroy, + &_pthread_mutex_lock, + &_pthread_mutex_trylock, + &_pthread_mutex_unlock +}; + + +/* + * Threaded process initialization + */ +void +_thread_init(void) +{ + int fd; + int flags; + int i; + size_t len; + int mib[2]; + struct clockinfo clockinfo; + struct sigaction act; + + /* Check if this function has already been called: */ + if (_thread_initial) + /* Only initialise the threaded application once. */ + return; + + /* + * Make gcc quiescent about {,libgcc_}references not being + * referenced: + */ + if ((references[0] == NULL) || (libgcc_references[0] == NULL)) + PANIC("Failed loading mandatory references in _thread_init"); + + /* + * Check for the special case of this process running as + * or in place of init as pid = 1: + */ + if (getpid() == 1) { + /* + * Setup a new session for this process which is + * assumed to be running as root. + */ + if (setsid() == -1) + PANIC("Can't set session ID"); + if (revoke(_PATH_CONSOLE) != 0) + PANIC("Can't revoke console"); + if ((fd = __sys_open(_PATH_CONSOLE, O_RDWR)) < 0) + PANIC("Can't open console"); + if (setlogin("root") == -1) + PANIC("Can't set login to root"); + if (__sys_ioctl(fd,TIOCSCTTY, (char *) NULL) == -1) + PANIC("Can't set controlling terminal"); + if (__sys_dup2(fd,0) == -1 || + __sys_dup2(fd,1) == -1 || + __sys_dup2(fd,2) == -1) + PANIC("Can't dup2"); + } + + /* Get the standard I/O flags before messing with them : */ + for (i = 0; i < 3; i++) + if (((_pthread_stdio_flags[i] = + __sys_fcntl(i,F_GETFL, NULL)) == -1) && + (errno != EBADF)) + PANIC("Cannot get stdio flags"); + + /* + * Create a pipe that is written to by the signal handler to prevent + * signals being missed in calls to _select: + */ + if (__sys_pipe(_thread_kern_pipe) != 0) { + /* Cannot create pipe, so abort: */ + PANIC("Cannot create kernel pipe"); + } + /* Get the flags for the read pipe: */ + else if ((flags = __sys_fcntl(_thread_kern_pipe[0], F_GETFL, NULL)) == -1) { + /* Abort this application: */ + PANIC("Cannot get kernel read pipe flags"); + } + /* Make the read pipe non-blocking: */ + else if (__sys_fcntl(_thread_kern_pipe[0], F_SETFL, flags | O_NONBLOCK) == -1) { + /* Abort this application: */ + PANIC("Cannot make kernel read pipe non-blocking"); + } + /* Get the flags for the write pipe: */ + else if ((flags = __sys_fcntl(_thread_kern_pipe[1], F_GETFL, NULL)) == -1) { + /* Abort this application: */ + PANIC("Cannot get kernel write pipe flags"); + } + /* Make the write pipe non-blocking: */ + else if (__sys_fcntl(_thread_kern_pipe[1], F_SETFL, flags | O_NONBLOCK) == -1) { + /* Abort this application: */ + PANIC("Cannot get kernel write pipe flags"); + } + /* Allocate and initialize the ready queue: */ + else if (_pq_alloc(&_readyq, PTHREAD_MIN_PRIORITY, PTHREAD_LAST_PRIORITY) != 0) { + /* Abort this application: */ + PANIC("Cannot allocate priority ready queue."); + } + /* Allocate memory for the thread structure of the initial thread: */ + else if ((_thread_initial = (pthread_t) malloc(sizeof(struct pthread))) == NULL) { + /* + * Insufficient memory to initialise this application, so + * abort: + */ + PANIC("Cannot allocate memory for initial thread"); + } + /* Allocate memory for the scheduler stack: */ + else if ((_thread_kern_sched_stack = malloc(SCHED_STACK_SIZE)) == NULL) + PANIC("Failed to allocate stack for scheduler"); + else { + /* Zero the global kernel thread structure: */ + memset(&_thread_kern_thread, 0, sizeof(struct pthread)); + _thread_kern_thread.flags = PTHREAD_FLAGS_PRIVATE; + memset(_thread_initial, 0, sizeof(struct pthread)); + + /* Initialize the waiting and work queues: */ + TAILQ_INIT(&_waitingq); + TAILQ_INIT(&_workq); + + /* Initialize the scheduling switch hook routine: */ + _sched_switch_hook = NULL; + + /* Give this thread default attributes: */ + memcpy((void *) &_thread_initial->attr, &pthread_attr_default, + sizeof(struct pthread_attr)); + + /* Find the stack top */ + mib[0] = CTL_KERN; + mib[1] = KERN_USRSTACK; + len = sizeof (_usrstack); + if (sysctl(mib, 2, &_usrstack, &len, NULL, 0) == -1) + _usrstack = (void *)USRSTACK; + /* + * Create a red zone below the main stack. All other stacks are + * constrained to a maximum size by the paramters passed to + * mmap(), but this stack is only limited by resource limits, so + * this stack needs an explicitly mapped red zone to protect the + * thread stack that is just beyond. + */ + if (mmap(_usrstack - PTHREAD_STACK_INITIAL - + PTHREAD_GUARD_DEFAULT, PTHREAD_GUARD_DEFAULT, 0, MAP_ANON, + -1, 0) == MAP_FAILED) + PANIC("Cannot allocate red zone for initial thread"); + + /* Set the main thread stack pointer. */ + _thread_initial->stack = _usrstack - PTHREAD_STACK_INITIAL; + + /* Set the stack attributes: */ + _thread_initial->attr.stackaddr_attr = _thread_initial->stack; + _thread_initial->attr.stacksize_attr = PTHREAD_STACK_INITIAL; + + /* Setup the context for the scheduler: */ + _setjmp(_thread_kern_sched_jb); + SET_STACK_JB(_thread_kern_sched_jb, _thread_kern_sched_stack + + SCHED_STACK_SIZE - sizeof(double)); + SET_RETURN_ADDR_JB(_thread_kern_sched_jb, _thread_kern_scheduler); + + /* + * Write a magic value to the thread structure + * to help identify valid ones: + */ + _thread_initial->magic = PTHREAD_MAGIC; + + /* Set the initial cancel state */ + _thread_initial->cancelflags = PTHREAD_CANCEL_ENABLE | + PTHREAD_CANCEL_DEFERRED; + + /* Default the priority of the initial thread: */ + _thread_initial->base_priority = PTHREAD_DEFAULT_PRIORITY; + _thread_initial->active_priority = PTHREAD_DEFAULT_PRIORITY; + _thread_initial->inherited_priority = 0; + + /* Initialise the state of the initial thread: */ + _thread_initial->state = PS_RUNNING; + + /* Set the name of the thread: */ + _thread_initial->name = strdup("_thread_initial"); + + /* Initialize joiner to NULL (no joiner): */ + _thread_initial->joiner = NULL; + + /* Initialize the owned mutex queue and count: */ + TAILQ_INIT(&(_thread_initial->mutexq)); + _thread_initial->priority_mutex_count = 0; + + /* Initialize the global scheduling time: */ + _sched_ticks = 0; + gettimeofday((struct timeval *) &_sched_tod, NULL); + + /* Initialize last active: */ + _thread_initial->last_active = (long) _sched_ticks; + + /* Initialize the initial context: */ + _thread_initial->curframe = NULL; + + /* Initialise the rest of the fields: */ + _thread_initial->poll_data.nfds = 0; + _thread_initial->poll_data.fds = NULL; + _thread_initial->sig_defer_count = 0; + _thread_initial->yield_on_sig_undefer = 0; + _thread_initial->specific = NULL; + _thread_initial->cleanup = NULL; + _thread_initial->flags = 0; + _thread_initial->error = 0; + TAILQ_INIT(&_thread_list); + TAILQ_INSERT_HEAD(&_thread_list, _thread_initial, tle); + _set_curthread(_thread_initial); + + /* Initialise the global signal action structure: */ + sigfillset(&act.sa_mask); + act.sa_handler = (void (*) ()) _thread_sig_handler; + act.sa_flags = SA_SIGINFO | SA_ONSTACK; + + /* Clear pending signals for the process: */ + sigemptyset(&_process_sigpending); + + /* Clear the signal queue: */ + memset(_thread_sigq, 0, sizeof(_thread_sigq)); + + /* Enter a loop to get the existing signal status: */ + for (i = 1; i < NSIG; i++) { + /* Check for signals which cannot be trapped: */ + if (i == SIGKILL || i == SIGSTOP) { + } + + /* Get the signal handler details: */ + else if (__sys_sigaction(i, NULL, + &_thread_sigact[i - 1]) != 0) { + /* + * Abort this process if signal + * initialisation fails: + */ + PANIC("Cannot read signal handler info"); + } + + /* Initialize the SIG_DFL dummy handler count. */ + _thread_dfl_count[i] = 0; + } + + /* + * Install the signal handler for the most important + * signals that the user-thread kernel needs. Actually + * SIGINFO isn't really needed, but it is nice to have. + */ + if (__sys_sigaction(_SCHED_SIGNAL, &act, NULL) != 0 || + __sys_sigaction(SIGINFO, &act, NULL) != 0 || + __sys_sigaction(SIGCHLD, &act, NULL) != 0) { + /* + * Abort this process if signal initialisation fails: + */ + PANIC("Cannot initialise signal handler"); + } + _thread_sigact[_SCHED_SIGNAL - 1].sa_flags = SA_SIGINFO; + _thread_sigact[SIGINFO - 1].sa_flags = SA_SIGINFO; + _thread_sigact[SIGCHLD - 1].sa_flags = SA_SIGINFO; + + /* Get the process signal mask: */ + __sys_sigprocmask(SIG_SETMASK, NULL, &_process_sigmask); + + /* Get the kernel clockrate: */ + mib[0] = CTL_KERN; + mib[1] = KERN_CLOCKRATE; + len = sizeof (struct clockinfo); + if (sysctl(mib, 2, &clockinfo, &len, NULL, 0) == 0) + _clock_res_usec = clockinfo.tick > CLOCK_RES_USEC_MIN ? + clockinfo.tick : CLOCK_RES_USEC_MIN; + + /* Get the table size: */ + if ((_thread_dtablesize = getdtablesize()) < 0) { + /* + * Cannot get the system defined table size, so abort + * this process. + */ + PANIC("Cannot get dtablesize"); + } + /* Allocate memory for the file descriptor table: */ + if ((_thread_fd_table = (struct fd_table_entry **) malloc(sizeof(struct fd_table_entry *) * _thread_dtablesize)) == NULL) { + /* Avoid accesses to file descriptor table on exit: */ + _thread_dtablesize = 0; + + /* + * Cannot allocate memory for the file descriptor + * table, so abort this process. + */ + PANIC("Cannot allocate memory for file descriptor table"); + } + /* Allocate memory for the pollfd table: */ + if ((_thread_pfd_table = (struct pollfd *) malloc(sizeof(struct pollfd) * _thread_dtablesize)) == NULL) { + /* + * Cannot allocate memory for the file descriptor + * table, so abort this process. + */ + PANIC("Cannot allocate memory for pollfd table"); + } else { + /* + * Enter a loop to initialise the file descriptor + * table: + */ + for (i = 0; i < _thread_dtablesize; i++) { + /* Initialise the file descriptor table: */ + _thread_fd_table[i] = NULL; + } + + /* Initialize stdio file descriptor table entries: */ + for (i = 0; i < 3; i++) { + if ((_thread_fd_table_init(i) != 0) && + (errno != EBADF)) + PANIC("Cannot initialize stdio file " + "descriptor table entry"); + } + } + } + + /* Initialise the garbage collector mutex and condition variable. */ + if (_pthread_mutex_init(&_gc_mutex,NULL) != 0 || + pthread_cond_init(&_gc_cond,NULL) != 0) + PANIC("Failed to initialise garbage collector mutex or condvar"); +} + +/* + * Special start up code for NetBSD/Alpha + */ +#if defined(__NetBSD__) && defined(__alpha__) +int +main(int argc, char *argv[], char *env); + +int +_thread_main(int argc, char *argv[], char *env) +{ + _thread_init(); + return (main(argc, argv, env)); +} +#endif diff --git a/lib/libc_r/uthread/uthread_ioctl.c b/lib/libc_r/uthread/uthread_ioctl.c new file mode 100644 index 0000000..9c7889f --- /dev/null +++ b/lib/libc_r/uthread/uthread_ioctl.c @@ -0,0 +1,79 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <stdarg.h> +#include <sys/ioctl.h> +#include <sys/fcntl.h> /* O_NONBLOCK*/ +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_ioctl, ioctl); + +int +_ioctl(int fd, unsigned long request,...) +{ + int ret; + int *op; + va_list ap; + + /* Lock the file descriptor: */ + if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) { + /* Initialise the variable argument list: */ + va_start(ap, request); + + switch( request) { + case FIONBIO: + /* + * descriptors must be non-blocking; we are only + * twiddling the flag based on the request + */ + op = va_arg(ap, int *); + _thread_fd_table[fd]->flags &= ~O_NONBLOCK; + _thread_fd_table[fd]->flags |= ((*op) ? O_NONBLOCK : 0); + ret = 0; + break; + default: + ret = __sys_ioctl(fd, request, va_arg(ap, char *)); + break; + } + + /* Free variable arguments: */ + va_end(ap); + + /* Unlock the file descriptor: */ + _FD_UNLOCK(fd, FD_RDWR); + } + + /* Return the completion status: */ + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_jmp.c b/lib/libc_r/uthread/uthread_jmp.c new file mode 100644 index 0000000..df9759f --- /dev/null +++ b/lib/libc_r/uthread/uthread_jmp.c @@ -0,0 +1,119 @@ +/* + * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. + * All rights reserved. + * Copyright (C) 2000 Daniel M. Eischen <eischen@vigrid.com>. + * 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(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) 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. + * + * $FreeBSD$ + */ + +#include <unistd.h> +#include <setjmp.h> +#include <sys/param.h> +#include <sys/user.h> +#include <machine/reg.h> +#include <pthread.h> +#include "pthread_private.h" + +/* Prototypes: */ +static inline int check_stack(pthread_t thread, void *stackp); + +__weak_reference(_thread_siglongjmp, siglongjmp); +__weak_reference(_thread_longjmp, longjmp); +__weak_reference(__thread_longjmp, _longjmp); + +void +_thread_siglongjmp(sigjmp_buf env, int savemask) +{ + struct pthread *curthread = _get_curthread(); + + if (check_stack(curthread, (void *) GET_STACK_SJB(env))) + PANIC("siglongjmp()ing between thread contexts is undefined by " + "POSIX 1003.1"); + + /* + * The stack pointer is somewhere within the threads stack. + * Jump to the users context. + */ + __siglongjmp(env, savemask); +} + +void +_thread_longjmp(jmp_buf env, int val) +{ + struct pthread *curthread = _get_curthread(); + + if (check_stack(curthread, (void *) GET_STACK_JB(env))) + PANIC("longjmp()ing between thread contexts is undefined by " + "POSIX 1003.1"); + + /* + * The stack pointer is somewhere within the threads stack. + * Jump to the users context. + */ + __longjmp(env, val); +} + +void +__thread_longjmp(jmp_buf env, int val) +{ + struct pthread *curthread = _get_curthread(); + + if (check_stack(curthread, (void *) GET_STACK_JB(env))) + PANIC("_longjmp()ing between thread contexts is undefined by " + "POSIX 1003.1"); + + /* + * The stack pointer is somewhere within the threads stack. + * Jump to the users context. + */ + ___longjmp(env, val); +} + +/* Returns 0 if stack check is OK, non-zero otherwise. */ +static inline int +check_stack(pthread_t thread, void *stackp) +{ + void *stack_begin, *stack_end; + + /* Get the bounds of the current threads stack. */ + PTHREAD_ASSERT(thread->stack != NULL, + "Thread stack pointer is null"); + stack_begin = thread->stack; + stack_end = stack_begin + thread->attr.stacksize_attr; + + /* + * Make sure we aren't jumping to a different stack. Make sure + * jmp_stackp is between stack_begin and stack end, to correctly detect + * this condition regardless of whether the stack grows up or down. + */ + if (((stackp < stack_begin) && (stackp < stack_end)) || + ((stackp > stack_begin) && (stackp > stack_end))) + return (1); + else + return (0); +} diff --git a/lib/libc_r/uthread/uthread_join.c b/lib/libc_r/uthread/uthread_join.c new file mode 100644 index 0000000..0f5e8fc --- /dev/null +++ b/lib/libc_r/uthread/uthread_join.c @@ -0,0 +1,162 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_join, pthread_join); + +int +_pthread_join(pthread_t pthread, void **thread_return) +{ + struct pthread *curthread = _get_curthread(); + int ret = 0; + pthread_t thread; + + _thread_enter_cancellation_point(); + + /* Check if the caller has specified an invalid thread: */ + if (pthread == NULL || pthread->magic != PTHREAD_MAGIC) { + /* Invalid thread: */ + _thread_leave_cancellation_point(); + return(EINVAL); + } + + /* Check if the caller has specified itself: */ + if (pthread == curthread) { + /* Avoid a deadlock condition: */ + _thread_leave_cancellation_point(); + return(EDEADLK); + } + + /* + * Lock the garbage collector mutex to ensure that the garbage + * collector is not using the dead thread list. + */ + if (pthread_mutex_lock(&_gc_mutex) != 0) + PANIC("Cannot lock gc mutex"); + + /* + * Defer signals to protect the thread list from access + * by the signal handler: + */ + _thread_kern_sig_defer(); + + /* + * Unlock the garbage collector mutex, now that the garbage collector + * can't be run: + */ + if (pthread_mutex_unlock(&_gc_mutex) != 0) + PANIC("Cannot lock gc mutex"); + + /* + * Search for the specified thread in the list of active threads. This + * is done manually here rather than calling _find_thread() because + * the searches in _thread_list and _dead_list (as well as setting up + * join/detach state) have to be done atomically. + */ + TAILQ_FOREACH(thread, &_thread_list, tle) { + if (thread == pthread) + break; + } + if (thread == NULL) { + /* + * Search for the specified thread in the list of dead threads: + */ + TAILQ_FOREACH(thread, &_dead_list, dle) { + if (thread == pthread) + break; + } + } + + /* Check if the thread was not found or has been detached: */ + if (thread == NULL || + ((pthread->attr.flags & PTHREAD_DETACHED) != 0)) { + /* Undefer and handle pending signals, yielding if necessary: */ + _thread_kern_sig_undefer(); + + /* Return an error: */ + ret = ESRCH; + + } else if (pthread->joiner != NULL) { + /* Undefer and handle pending signals, yielding if necessary: */ + _thread_kern_sig_undefer(); + + /* Multiple joiners are not supported. */ + ret = ENOTSUP; + + /* Check if the thread is not dead: */ + } else if (pthread->state != PS_DEAD) { + /* Set the running thread to be the joiner: */ + pthread->joiner = curthread; + + /* Keep track of which thread we're joining to: */ + curthread->join_status.thread = pthread; + + while (curthread->join_status.thread == pthread) { + /* Schedule the next thread: */ + _thread_kern_sched_state(PS_JOIN, __FILE__, __LINE__); + } + + /* + * The thread return value and error are set by the thread we're + * joining to when it exits or detaches: + */ + ret = curthread->join_status.error; + if ((ret == 0) && (thread_return != NULL)) + *thread_return = curthread->join_status.ret; + } else { + /* + * The thread exited (is dead) without being detached, and no + * thread has joined it. + */ + + /* Check if the return value is required: */ + if (thread_return != NULL) { + /* Return the thread's return value: */ + *thread_return = pthread->ret; + } + + /* Make the thread collectable by the garbage collector. */ + pthread->attr.flags |= PTHREAD_DETACHED; + + /* Undefer and handle pending signals, yielding if necessary: */ + _thread_kern_sig_undefer(); + } + + _thread_leave_cancellation_point(); + + /* Return the completion status: */ + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_kern.c b/lib/libc_r/uthread/uthread_kern.c new file mode 100644 index 0000000..a4cc3c3 --- /dev/null +++ b/lib/libc_r/uthread/uthread_kern.c @@ -0,0 +1,1139 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + * + */ +#include <errno.h> +#include <poll.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <unistd.h> +#include <setjmp.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/signalvar.h> +#include <sys/stat.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <sys/syscall.h> +#include <fcntl.h> +#include <pthread.h> +#include "pthread_private.h" + +/* #define DEBUG_THREAD_KERN */ +#ifdef DEBUG_THREAD_KERN +#define DBG_MSG stdout_debug +#else +#define DBG_MSG(x...) +#endif + +/* Static function prototype definitions: */ +static void +thread_kern_poll(int wait_reqd); + +static void +dequeue_signals(void); + +static inline void +thread_run_switch_hook(pthread_t thread_out, pthread_t thread_in); + +/* Static variables: */ +static int last_tick = 0; +static int called_from_handler = 0; + +/* + * This is called when a signal handler finishes and wants to + * return to a previous frame. + */ +void +_thread_kern_sched_frame(struct pthread_signal_frame *psf) +{ + struct pthread *curthread = _get_curthread(); + + /* + * Flag the pthread kernel as executing scheduler code + * to avoid a signal from interrupting this execution and + * corrupting the (soon-to-be) current frame. + */ + _thread_kern_in_sched = 1; + + /* Restore the signal frame: */ + _thread_sigframe_restore(curthread, psf); + + /* The signal mask was restored; check for any pending signals: */ + curthread->check_pending = 1; + + /* Switch to the thread scheduler: */ + ___longjmp(_thread_kern_sched_jb, 1); +} + + +void +_thread_kern_sched(ucontext_t *ucp) +{ + struct pthread *curthread = _get_curthread(); + + /* + * Flag the pthread kernel as executing scheduler code + * to avoid a scheduler signal from interrupting this + * execution and calling the scheduler again. + */ + _thread_kern_in_sched = 1; + + /* Check if this function was called from the signal handler: */ + if (ucp != NULL) { + /* XXX - Save FP registers? */ + FP_SAVE_UC(ucp); + called_from_handler = 1; + DBG_MSG("Entering scheduler due to signal\n"); + } + + /* Save the state of the current thread: */ + if (_setjmp(curthread->ctx.jb) != 0) { + DBG_MSG("Returned from ___longjmp, thread %p\n", + curthread); + /* + * This point is reached when a longjmp() is called + * to restore the state of a thread. + * + * This is the normal way out of the scheduler. + */ + _thread_kern_in_sched = 0; + + if (curthread->sig_defer_count == 0) { + if (((curthread->cancelflags & + PTHREAD_AT_CANCEL_POINT) == 0) && + ((curthread->cancelflags & + PTHREAD_CANCEL_ASYNCHRONOUS) != 0)) + /* + * Cancellations override signals. + * + * Stick a cancellation point at the + * start of each async-cancellable + * thread's resumption. + * + * We allow threads woken at cancel + * points to do their own checks. + */ + pthread_testcancel(); + } + + if (_sched_switch_hook != NULL) { + /* Run the installed switch hook: */ + thread_run_switch_hook(_last_user_thread, curthread); + } + if (ucp == NULL) + return; + else { + /* XXX - Restore FP registers? */ + FP_RESTORE_UC(ucp); + + /* + * Set the process signal mask in the context; it + * could have changed by the handler. + */ + ucp->uc_sigmask = _process_sigmask; + + /* Resume the interrupted thread: */ + __sys_sigreturn(ucp); + } + } + /* Switch to the thread scheduler: */ + ___longjmp(_thread_kern_sched_jb, 1); +} + +void +_thread_kern_sched_sig(void) +{ + struct pthread *curthread = _get_curthread(); + + curthread->check_pending = 1; + _thread_kern_sched(NULL); +} + + +void +_thread_kern_scheduler(void) +{ + struct timespec ts; + struct timeval tv; + struct pthread *curthread = _get_curthread(); + pthread_t pthread, pthread_h; + unsigned int current_tick; + int add_to_prioq; + + /* If the currently running thread is a user thread, save it: */ + if ((curthread->flags & PTHREAD_FLAGS_PRIVATE) == 0) + _last_user_thread = curthread; + + if (called_from_handler != 0) { + called_from_handler = 0; + + /* + * We were called from a signal handler; restore the process + * signal mask. + */ + if (__sys_sigprocmask(SIG_SETMASK, + &_process_sigmask, NULL) != 0) + PANIC("Unable to restore process mask after signal"); + } + + /* + * Enter a scheduling loop that finds the next thread that is + * ready to run. This loop completes when there are no more threads + * in the global list or when a thread has its state restored by + * either a sigreturn (if the state was saved as a sigcontext) or a + * longjmp (if the state was saved by a setjmp). + */ + while (!(TAILQ_EMPTY(&_thread_list))) { + /* Get the current time of day: */ + GET_CURRENT_TOD(tv); + TIMEVAL_TO_TIMESPEC(&tv, &ts); + current_tick = _sched_ticks; + + /* + * Protect the scheduling queues from access by the signal + * handler. + */ + _queue_signals = 1; + add_to_prioq = 0; + + if (curthread != &_thread_kern_thread) { + /* + * This thread no longer needs to yield the CPU. + */ + curthread->yield_on_sig_undefer = 0; + + if (curthread->state != PS_RUNNING) { + /* + * Save the current time as the time that the + * thread became inactive: + */ + curthread->last_inactive = (long)current_tick; + if (curthread->last_inactive < + curthread->last_active) { + /* Account for a rollover: */ + curthread->last_inactive =+ + UINT_MAX + 1; + } + } + + /* + * Place the currently running thread into the + * appropriate queue(s). + */ + switch (curthread->state) { + case PS_DEAD: + case PS_STATE_MAX: /* to silence -Wall */ + case PS_SUSPENDED: + /* + * Dead and suspended threads are not placed + * in any queue: + */ + break; + + case PS_RUNNING: + /* + * Runnable threads can't be placed in the + * priority queue until after waiting threads + * are polled (to preserve round-robin + * scheduling). + */ + add_to_prioq = 1; + break; + + /* + * States which do not depend on file descriptor I/O + * operations or timeouts: + */ + case PS_DEADLOCK: + case PS_FDLR_WAIT: + case PS_FDLW_WAIT: + case PS_FILE_WAIT: + case PS_JOIN: + case PS_MUTEX_WAIT: + case PS_SIGSUSPEND: + case PS_SIGTHREAD: + case PS_SIGWAIT: + case PS_WAIT_WAIT: + /* No timeouts for these states: */ + curthread->wakeup_time.tv_sec = -1; + curthread->wakeup_time.tv_nsec = -1; + + /* Restart the time slice: */ + curthread->slice_usec = -1; + + /* Insert into the waiting queue: */ + PTHREAD_WAITQ_INSERT(curthread); + break; + + /* States which can timeout: */ + case PS_COND_WAIT: + case PS_SLEEP_WAIT: + /* Restart the time slice: */ + curthread->slice_usec = -1; + + /* Insert into the waiting queue: */ + PTHREAD_WAITQ_INSERT(curthread); + break; + + /* States that require periodic work: */ + case PS_SPINBLOCK: + /* No timeouts for this state: */ + curthread->wakeup_time.tv_sec = -1; + curthread->wakeup_time.tv_nsec = -1; + + /* Increment spinblock count: */ + _spinblock_count++; + + /* FALLTHROUGH */ + case PS_FDR_WAIT: + case PS_FDW_WAIT: + case PS_POLL_WAIT: + case PS_SELECT_WAIT: + /* Restart the time slice: */ + curthread->slice_usec = -1; + + /* Insert into the waiting queue: */ + PTHREAD_WAITQ_INSERT(curthread); + + /* Insert into the work queue: */ + PTHREAD_WORKQ_INSERT(curthread); + break; + } + + /* + * Are there pending signals for this thread? + * + * This check has to be performed after the thread + * has been placed in the queue(s) appropriate for + * its state. The process of adding pending signals + * can change a threads state, which in turn will + * attempt to add or remove the thread from any + * scheduling queue to which it belongs. + */ + if (curthread->check_pending != 0) { + curthread->check_pending = 0; + _thread_sig_check_pending(curthread); + } + } + + /* + * Avoid polling file descriptors if there are none + * waiting: + */ + if (TAILQ_EMPTY(&_workq) != 0) { + } + /* + * Poll file descriptors only if a new scheduling signal + * has occurred or if we have no more runnable threads. + */ + else if (((current_tick = _sched_ticks) != last_tick) || + ((curthread->state != PS_RUNNING) && + (PTHREAD_PRIOQ_FIRST() == NULL))) { + /* Unprotect the scheduling queues: */ + _queue_signals = 0; + + /* + * Poll file descriptors to update the state of threads + * waiting on file I/O where data may be available: + */ + thread_kern_poll(0); + + /* Protect the scheduling queues: */ + _queue_signals = 1; + } + last_tick = current_tick; + + /* + * Wake up threads that have timedout. This has to be + * done after polling in case a thread does a poll or + * select with zero time. + */ + PTHREAD_WAITQ_SETACTIVE(); + while (((pthread = TAILQ_FIRST(&_waitingq)) != NULL) && + (pthread->wakeup_time.tv_sec != -1) && + (((pthread->wakeup_time.tv_sec == 0) && + (pthread->wakeup_time.tv_nsec == 0)) || + (pthread->wakeup_time.tv_sec < ts.tv_sec) || + ((pthread->wakeup_time.tv_sec == ts.tv_sec) && + (pthread->wakeup_time.tv_nsec <= ts.tv_nsec)))) { + switch (pthread->state) { + case PS_POLL_WAIT: + case PS_SELECT_WAIT: + /* Return zero file descriptors ready: */ + pthread->data.poll_data->nfds = 0; + /* fall through */ + default: + /* + * Remove this thread from the waiting queue + * (and work queue if necessary) and place it + * in the ready queue. + */ + PTHREAD_WAITQ_CLEARACTIVE(); + if (pthread->flags & PTHREAD_FLAGS_IN_WORKQ) + PTHREAD_WORKQ_REMOVE(pthread); + PTHREAD_NEW_STATE(pthread, PS_RUNNING); + PTHREAD_WAITQ_SETACTIVE(); + break; + } + /* + * Flag the timeout in the thread structure: + */ + pthread->timeout = 1; + } + PTHREAD_WAITQ_CLEARACTIVE(); + + /* + * Check to see if the current thread needs to be added + * to the priority queue: + */ + if (add_to_prioq != 0) { + /* + * Save the current time as the time that the + * thread became inactive: + */ + current_tick = _sched_ticks; + curthread->last_inactive = (long)current_tick; + if (curthread->last_inactive < + curthread->last_active) { + /* Account for a rollover: */ + curthread->last_inactive =+ UINT_MAX + 1; + } + + if ((curthread->slice_usec != -1) && + (curthread->attr.sched_policy != SCHED_FIFO)) { + /* + * Accumulate the number of microseconds for + * which the current thread has run: + */ + curthread->slice_usec += + (curthread->last_inactive - + curthread->last_active) * + (long)_clock_res_usec; + /* Check for time quantum exceeded: */ + if (curthread->slice_usec > TIMESLICE_USEC) + curthread->slice_usec = -1; + } + + if (curthread->slice_usec == -1) { + /* + * The thread exceeded its time + * quantum or it yielded the CPU; + * place it at the tail of the + * queue for its priority. + */ + PTHREAD_PRIOQ_INSERT_TAIL(curthread); + } else { + /* + * The thread hasn't exceeded its + * interval. Place it at the head + * of the queue for its priority. + */ + PTHREAD_PRIOQ_INSERT_HEAD(curthread); + } + } + + /* + * Get the highest priority thread in the ready queue. + */ + pthread_h = PTHREAD_PRIOQ_FIRST(); + + /* Check if there are no threads ready to run: */ + if (pthread_h == NULL) { + /* + * Lock the pthread kernel by changing the pointer to + * the running thread to point to the global kernel + * thread structure: + */ + _set_curthread(&_thread_kern_thread); + curthread = &_thread_kern_thread; + + DBG_MSG("No runnable threads, using kernel thread %p\n", + curthread); + + /* Unprotect the scheduling queues: */ + _queue_signals = 0; + + /* + * There are no threads ready to run, so wait until + * something happens that changes this condition: + */ + thread_kern_poll(1); + + /* + * This process' usage will likely be very small + * while waiting in a poll. Since the scheduling + * clock is based on the profiling timer, it is + * unlikely that the profiling timer will fire + * and update the time of day. To account for this, + * get the time of day after polling with a timeout. + */ + gettimeofday((struct timeval *) &_sched_tod, NULL); + + /* Check once more for a runnable thread: */ + _queue_signals = 1; + pthread_h = PTHREAD_PRIOQ_FIRST(); + _queue_signals = 0; + } + + if (pthread_h != NULL) { + /* Remove the thread from the ready queue: */ + PTHREAD_PRIOQ_REMOVE(pthread_h); + + /* Unprotect the scheduling queues: */ + _queue_signals = 0; + + /* + * Check for signals queued while the scheduling + * queues were protected: + */ + while (_sigq_check_reqd != 0) { + /* Clear before handling queued signals: */ + _sigq_check_reqd = 0; + + /* Protect the scheduling queues again: */ + _queue_signals = 1; + + dequeue_signals(); + + /* + * Check for a higher priority thread that + * became runnable due to signal handling. + */ + if (((pthread = PTHREAD_PRIOQ_FIRST()) != NULL) && + (pthread->active_priority > pthread_h->active_priority)) { + /* Remove the thread from the ready queue: */ + PTHREAD_PRIOQ_REMOVE(pthread); + + /* + * Insert the lower priority thread + * at the head of its priority list: + */ + PTHREAD_PRIOQ_INSERT_HEAD(pthread_h); + + /* There's a new thread in town: */ + pthread_h = pthread; + } + + /* Unprotect the scheduling queues: */ + _queue_signals = 0; + } + + /* Make the selected thread the current thread: */ + _set_curthread(pthread_h); + curthread = pthread_h; + + /* + * Save the current time as the time that the thread + * became active: + */ + current_tick = _sched_ticks; + curthread->last_active = (long) current_tick; + + /* + * Check if this thread is running for the first time + * or running again after using its full time slice + * allocation: + */ + if (curthread->slice_usec == -1) { + /* Reset the accumulated time slice period: */ + curthread->slice_usec = 0; + } + + /* + * If we had a context switch, run any + * installed switch hooks. + */ + if ((_sched_switch_hook != NULL) && + (_last_user_thread != curthread)) { + thread_run_switch_hook(_last_user_thread, + curthread); + } + /* + * Continue the thread at its current frame: + */ +#if NOT_YET + _setcontext(&curthread->ctx.uc); +#else + ___longjmp(curthread->ctx.jb, 1); +#endif + /* This point should not be reached. */ + PANIC("Thread has returned from sigreturn or longjmp"); + } + } + + /* There are no more threads, so exit this process: */ + exit(0); +} + +void +_thread_kern_sched_state(enum pthread_state state, char *fname, int lineno) +{ + struct pthread *curthread = _get_curthread(); + + /* + * Flag the pthread kernel as executing scheduler code + * to avoid a scheduler signal from interrupting this + * execution and calling the scheduler again. + */ + _thread_kern_in_sched = 1; + + /* + * Prevent the signal handler from fiddling with this thread + * before its state is set and is placed into the proper queue. + */ + _queue_signals = 1; + + /* Change the state of the current thread: */ + curthread->state = state; + curthread->fname = fname; + curthread->lineno = lineno; + + /* Schedule the next thread that is ready: */ + _thread_kern_sched(NULL); +} + +void +_thread_kern_sched_state_unlock(enum pthread_state state, + spinlock_t *lock, char *fname, int lineno) +{ + struct pthread *curthread = _get_curthread(); + + /* + * Flag the pthread kernel as executing scheduler code + * to avoid a scheduler signal from interrupting this + * execution and calling the scheduler again. + */ + _thread_kern_in_sched = 1; + + /* + * Prevent the signal handler from fiddling with this thread + * before its state is set and it is placed into the proper + * queue(s). + */ + _queue_signals = 1; + + /* Change the state of the current thread: */ + curthread->state = state; + curthread->fname = fname; + curthread->lineno = lineno; + + _SPINUNLOCK(lock); + + /* Schedule the next thread that is ready: */ + _thread_kern_sched(NULL); +} + +static void +thread_kern_poll(int wait_reqd) +{ + int count = 0; + int i, found; + int kern_pipe_added = 0; + int nfds = 0; + int timeout_ms = 0; + struct pthread *pthread; + struct timespec ts; + struct timeval tv; + + /* Check if the caller wants to wait: */ + if (wait_reqd == 0) { + timeout_ms = 0; + } + else { + /* Get the current time of day: */ + GET_CURRENT_TOD(tv); + TIMEVAL_TO_TIMESPEC(&tv, &ts); + + _queue_signals = 1; + pthread = TAILQ_FIRST(&_waitingq); + _queue_signals = 0; + + if ((pthread == NULL) || (pthread->wakeup_time.tv_sec == -1)) { + /* + * Either there are no threads in the waiting queue, + * or there are no threads that can timeout. + */ + timeout_ms = INFTIM; + } + else if (pthread->wakeup_time.tv_sec - ts.tv_sec > 60000) + /* Limit maximum timeout to prevent rollover. */ + timeout_ms = 60000; + else { + /* + * Calculate the time left for the next thread to + * timeout: + */ + timeout_ms = ((pthread->wakeup_time.tv_sec - ts.tv_sec) * + 1000) + ((pthread->wakeup_time.tv_nsec - ts.tv_nsec) / + 1000000); + /* + * Don't allow negative timeouts: + */ + if (timeout_ms < 0) + timeout_ms = 0; + } + } + + /* Protect the scheduling queues: */ + _queue_signals = 1; + + /* + * Check to see if the signal queue needs to be walked to look + * for threads awoken by a signal while in the scheduler. + */ + if (_sigq_check_reqd != 0) { + /* Reset flag before handling queued signals: */ + _sigq_check_reqd = 0; + + dequeue_signals(); + } + + /* + * Check for a thread that became runnable due to a signal: + */ + if (PTHREAD_PRIOQ_FIRST() != NULL) { + /* + * Since there is at least one runnable thread, + * disable the wait. + */ + timeout_ms = 0; + } + + /* + * Form the poll table: + */ + nfds = 0; + if (timeout_ms != 0) { + /* Add the kernel pipe to the poll table: */ + _thread_pfd_table[nfds].fd = _thread_kern_pipe[0]; + _thread_pfd_table[nfds].events = POLLRDNORM; + _thread_pfd_table[nfds].revents = 0; + nfds++; + kern_pipe_added = 1; + } + + PTHREAD_WAITQ_SETACTIVE(); + TAILQ_FOREACH(pthread, &_workq, qe) { + switch (pthread->state) { + case PS_SPINBLOCK: + /* + * If the lock is available, let the thread run. + */ + if (pthread->data.spinlock->access_lock == 0) { + PTHREAD_WAITQ_CLEARACTIVE(); + PTHREAD_WORKQ_REMOVE(pthread); + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + PTHREAD_WAITQ_SETACTIVE(); + /* One less thread in a spinblock state: */ + _spinblock_count--; + /* + * Since there is at least one runnable + * thread, disable the wait. + */ + timeout_ms = 0; + } + break; + + /* File descriptor read wait: */ + case PS_FDR_WAIT: + /* Limit number of polled files to table size: */ + if (nfds < _thread_dtablesize) { + _thread_pfd_table[nfds].events = POLLRDNORM; + _thread_pfd_table[nfds].fd = pthread->data.fd.fd; + nfds++; + } + break; + + /* File descriptor write wait: */ + case PS_FDW_WAIT: + /* Limit number of polled files to table size: */ + if (nfds < _thread_dtablesize) { + _thread_pfd_table[nfds].events = POLLWRNORM; + _thread_pfd_table[nfds].fd = pthread->data.fd.fd; + nfds++; + } + break; + + /* File descriptor poll or select wait: */ + case PS_POLL_WAIT: + case PS_SELECT_WAIT: + /* Limit number of polled files to table size: */ + if (pthread->data.poll_data->nfds + nfds < + _thread_dtablesize) { + for (i = 0; i < pthread->data.poll_data->nfds; i++) { + _thread_pfd_table[nfds + i].fd = + pthread->data.poll_data->fds[i].fd; + _thread_pfd_table[nfds + i].events = + pthread->data.poll_data->fds[i].events; + } + nfds += pthread->data.poll_data->nfds; + } + break; + + /* Other states do not depend on file I/O. */ + default: + break; + } + } + PTHREAD_WAITQ_CLEARACTIVE(); + + /* + * Wait for a file descriptor to be ready for read, write, or + * an exception, or a timeout to occur: + */ + count = __sys_poll(_thread_pfd_table, nfds, timeout_ms); + + if (kern_pipe_added != 0) + /* + * Remove the pthread kernel pipe file descriptor + * from the pollfd table: + */ + nfds = 1; + else + nfds = 0; + + /* + * Check if it is possible that there are bytes in the kernel + * read pipe waiting to be read: + */ + if (count < 0 || ((kern_pipe_added != 0) && + (_thread_pfd_table[0].revents & POLLRDNORM))) { + /* + * If the kernel read pipe was included in the + * count: + */ + if (count > 0) { + /* Decrement the count of file descriptors: */ + count--; + } + + if (_sigq_check_reqd != 0) { + /* Reset flag before handling signals: */ + _sigq_check_reqd = 0; + + dequeue_signals(); + } + } + + /* + * Check if any file descriptors are ready: + */ + if (count > 0) { + /* + * Enter a loop to look for threads waiting on file + * descriptors that are flagged as available by the + * _poll syscall: + */ + PTHREAD_WAITQ_SETACTIVE(); + TAILQ_FOREACH(pthread, &_workq, qe) { + switch (pthread->state) { + case PS_SPINBLOCK: + /* + * If the lock is available, let the thread run. + */ + if (pthread->data.spinlock->access_lock == 0) { + PTHREAD_WAITQ_CLEARACTIVE(); + PTHREAD_WORKQ_REMOVE(pthread); + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + PTHREAD_WAITQ_SETACTIVE(); + + /* + * One less thread in a spinblock state: + */ + _spinblock_count--; + } + break; + + /* File descriptor read wait: */ + case PS_FDR_WAIT: + if ((nfds < _thread_dtablesize) && + (_thread_pfd_table[nfds].revents & POLLRDNORM)) { + PTHREAD_WAITQ_CLEARACTIVE(); + PTHREAD_WORKQ_REMOVE(pthread); + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + PTHREAD_WAITQ_SETACTIVE(); + } + nfds++; + break; + + /* File descriptor write wait: */ + case PS_FDW_WAIT: + if ((nfds < _thread_dtablesize) && + (_thread_pfd_table[nfds].revents & POLLWRNORM)) { + PTHREAD_WAITQ_CLEARACTIVE(); + PTHREAD_WORKQ_REMOVE(pthread); + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + PTHREAD_WAITQ_SETACTIVE(); + } + nfds++; + break; + + /* File descriptor poll or select wait: */ + case PS_POLL_WAIT: + case PS_SELECT_WAIT: + if (pthread->data.poll_data->nfds + nfds < + _thread_dtablesize) { + /* + * Enter a loop looking for I/O + * readiness: + */ + found = 0; + for (i = 0; i < pthread->data.poll_data->nfds; i++) { + if (_thread_pfd_table[nfds + i].revents != 0) { + pthread->data.poll_data->fds[i].revents = + _thread_pfd_table[nfds + i].revents; + found++; + } + } + + /* Increment before destroying: */ + nfds += pthread->data.poll_data->nfds; + + if (found != 0) { + pthread->data.poll_data->nfds = found; + PTHREAD_WAITQ_CLEARACTIVE(); + PTHREAD_WORKQ_REMOVE(pthread); + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + PTHREAD_WAITQ_SETACTIVE(); + } + } + else + nfds += pthread->data.poll_data->nfds; + break; + + /* Other states do not depend on file I/O. */ + default: + break; + } + } + PTHREAD_WAITQ_CLEARACTIVE(); + } + else if (_spinblock_count != 0) { + /* + * Enter a loop to look for threads waiting on a spinlock + * that is now available. + */ + PTHREAD_WAITQ_SETACTIVE(); + TAILQ_FOREACH(pthread, &_workq, qe) { + if (pthread->state == PS_SPINBLOCK) { + /* + * If the lock is available, let the thread run. + */ + if (pthread->data.spinlock->access_lock == 0) { + PTHREAD_WAITQ_CLEARACTIVE(); + PTHREAD_WORKQ_REMOVE(pthread); + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + PTHREAD_WAITQ_SETACTIVE(); + + /* + * One less thread in a spinblock state: + */ + _spinblock_count--; + } + } + } + PTHREAD_WAITQ_CLEARACTIVE(); + } + + /* Unprotect the scheduling queues: */ + _queue_signals = 0; + + while (_sigq_check_reqd != 0) { + /* Handle queued signals: */ + _sigq_check_reqd = 0; + + /* Protect the scheduling queues: */ + _queue_signals = 1; + + dequeue_signals(); + + /* Unprotect the scheduling queues: */ + _queue_signals = 0; + } +} + +void +_thread_kern_set_timeout(const struct timespec * timeout) +{ + struct pthread *curthread = _get_curthread(); + struct timespec current_time; + struct timeval tv; + + /* Reset the timeout flag for the running thread: */ + curthread->timeout = 0; + + /* Check if the thread is to wait forever: */ + if (timeout == NULL) { + /* + * Set the wakeup time to something that can be recognised as + * different to an actual time of day: + */ + curthread->wakeup_time.tv_sec = -1; + curthread->wakeup_time.tv_nsec = -1; + } + /* Check if no waiting is required: */ + else if (timeout->tv_sec == 0 && timeout->tv_nsec == 0) { + /* Set the wake up time to 'immediately': */ + curthread->wakeup_time.tv_sec = 0; + curthread->wakeup_time.tv_nsec = 0; + } else { + /* Get the current time: */ + GET_CURRENT_TOD(tv); + TIMEVAL_TO_TIMESPEC(&tv, ¤t_time); + + /* Calculate the time for the current thread to wake up: */ + curthread->wakeup_time.tv_sec = current_time.tv_sec + timeout->tv_sec; + curthread->wakeup_time.tv_nsec = current_time.tv_nsec + timeout->tv_nsec; + + /* Check if the nanosecond field needs to wrap: */ + if (curthread->wakeup_time.tv_nsec >= 1000000000) { + /* Wrap the nanosecond field: */ + curthread->wakeup_time.tv_sec += 1; + curthread->wakeup_time.tv_nsec -= 1000000000; + } + } +} + +void +_thread_kern_sig_defer(void) +{ + struct pthread *curthread = _get_curthread(); + + /* Allow signal deferral to be recursive. */ + curthread->sig_defer_count++; +} + +void +_thread_kern_sig_undefer(void) +{ + struct pthread *curthread = _get_curthread(); + + /* + * Perform checks to yield only if we are about to undefer + * signals. + */ + if (curthread->sig_defer_count > 1) { + /* Decrement the signal deferral count. */ + curthread->sig_defer_count--; + } + else if (curthread->sig_defer_count == 1) { + /* Reenable signals: */ + curthread->sig_defer_count = 0; + + /* + * Check if there are queued signals: + */ + if (_sigq_check_reqd != 0) + _thread_kern_sched(NULL); + + /* + * Check for asynchronous cancellation before delivering any + * pending signals: + */ + if (((curthread->cancelflags & PTHREAD_AT_CANCEL_POINT) == 0) && + ((curthread->cancelflags & PTHREAD_CANCEL_ASYNCHRONOUS) != 0)) + pthread_testcancel(); + + /* + * If there are pending signals or this thread has + * to yield the CPU, call the kernel scheduler: + * + * XXX - Come back and revisit the pending signal problem + */ + if ((curthread->yield_on_sig_undefer != 0) || + SIGNOTEMPTY(curthread->sigpend)) { + curthread->yield_on_sig_undefer = 0; + _thread_kern_sched(NULL); + } + } +} + +static void +dequeue_signals(void) +{ + char bufr[128]; + int num; + + /* + * Enter a loop to clear the pthread kernel pipe: + */ + while (((num = __sys_read(_thread_kern_pipe[0], bufr, + sizeof(bufr))) > 0) || (num == -1 && errno == EINTR)) { + } + if ((num < 0) && (errno != EAGAIN)) { + /* + * The only error we should expect is if there is + * no data to read. + */ + PANIC("Unable to read from thread kernel pipe"); + } + /* Handle any pending signals: */ + _thread_sig_handle_pending(); +} + +static inline void +thread_run_switch_hook(pthread_t thread_out, pthread_t thread_in) +{ + pthread_t tid_out = thread_out; + pthread_t tid_in = thread_in; + + if ((tid_out != NULL) && + (tid_out->flags & PTHREAD_FLAGS_PRIVATE) != 0) + tid_out = NULL; + if ((tid_in != NULL) && + (tid_in->flags & PTHREAD_FLAGS_PRIVATE) != 0) + tid_in = NULL; + + if ((_sched_switch_hook != NULL) && (tid_out != tid_in)) { + /* Run the scheduler switch hook: */ + _sched_switch_hook(tid_out, tid_in); + } +} + +struct pthread * +_get_curthread(void) +{ + if (_thread_initial == NULL) + _thread_init(); + + return (_thread_run); +} + +void +_set_curthread(struct pthread *newthread) +{ + _thread_run = newthread; +} diff --git a/lib/libc_r/uthread/uthread_kevent.c b/lib/libc_r/uthread/uthread_kevent.c new file mode 100644 index 0000000..17aeaea --- /dev/null +++ b/lib/libc_r/uthread/uthread_kevent.c @@ -0,0 +1,77 @@ +/*- + * Copyright (c) 2000 Jonathan Lemon <jlemon@flugsvamp.com> + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include <unistd.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/event.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_kevent, kevent); + +int +_kevent(int kq, const struct kevent *changelist, int nchanges, + struct kevent *eventlist, int nevents, const struct timespec *timeout) +{ + struct pthread *curthread = _get_curthread(); + struct timespec nullts = { 0, 0 }; + int rc; + + /* Set the wake up time */ + _thread_kern_set_timeout(timeout); + + rc = __sys_kevent(kq, changelist, nchanges, + eventlist, nevents, &nullts); + if (rc == 0 && eventlist != NULL && nevents > 0 && (timeout == NULL || + timeout->tv_sec != 0 || timeout->tv_nsec != 0)) { + /* Save the socket file descriptor: */ + curthread->data.fd.fd = kq; + curthread->data.fd.fname = __FILE__; + curthread->data.fd.branch = __LINE__; + + do { + /* Reset the interrupted and timeout flags: */ + curthread->interrupted = 0; + curthread->timeout = 0; + + _thread_kern_sched_state(PS_FDR_WAIT, + __FILE__, __LINE__); + + if (curthread->interrupted) { + errno = EINTR; + rc = -1; + break; + } + rc = __sys_kevent(kq, NULL, 0, + eventlist, nevents, &nullts); + } while (rc == 0 && curthread->timeout == 0); + } + return (rc); +} diff --git a/lib/libc_r/uthread/uthread_kill.c b/lib/libc_r/uthread/uthread_kill.c new file mode 100644 index 0000000..29e1814 --- /dev/null +++ b/lib/libc_r/uthread/uthread_kill.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 1997 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <signal.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_kill, pthread_kill); + +int +_pthread_kill(pthread_t pthread, int sig) +{ + int ret; + + /* Check for invalid signal numbers: */ + if (sig < 0 || sig >= NSIG) + /* Invalid signal: */ + ret = EINVAL; + /* + * Ensure the thread is in the list of active threads, and the + * signal is valid (signal 0 specifies error checking only) and + * not being ignored: + */ + else if (((ret = _find_thread(pthread)) == 0) && (sig > 0) && + (_thread_sigact[sig - 1].sa_handler != SIG_IGN)) { + /* + * Defer signals to protect the scheduling queues from + * access by the signal handler: + */ + _thread_kern_sig_defer(); + + _thread_sig_send(pthread, sig); + + /* + * Undefer and handle pending signals, yielding if + * necessary: + */ + _thread_kern_sig_undefer(); + } + + /* Return the completion status: */ + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_listen.c b/lib/libc_r/uthread/uthread_listen.c new file mode 100644 index 0000000..0b73ab2 --- /dev/null +++ b/lib/libc_r/uthread/uthread_listen.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <sys/types.h> +#include <sys/socket.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_listen, listen); + +int +_listen(int fd, int backlog) +{ + int ret; + + if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) { + ret = __sys_listen(fd, backlog); + _FD_UNLOCK(fd, FD_RDWR); + } + return (ret); +} + diff --git a/lib/libc_r/uthread/uthread_main_np.c b/lib/libc_r/uthread/uthread_main_np.c new file mode 100644 index 0000000..6ae7d1e --- /dev/null +++ b/lib/libc_r/uthread/uthread_main_np.c @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2001 Alfred Perlstein + * Author: Alfred Perlstein <alfred@FreeBSD.org> + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include <pthread.h> +#include <pthread_np.h> +#include "pthread_private.h" + +/* + * Provide the equivelant to Solaris thr_main() function + */ +#pragma weak pthread_main_np=_pthread_main_np +int +_pthread_main_np() +{ + + if (!_thread_initial) + return (-1); + else + return (pthread_equal(pthread_self(), _thread_initial) ? 1 : 0); +} diff --git a/lib/libc_r/uthread/uthread_mattr_init.c b/lib/libc_r/uthread/uthread_mattr_init.c new file mode 100644 index 0000000..e4e2e50 --- /dev/null +++ b/lib/libc_r/uthread/uthread_mattr_init.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1996 Jeffrey Hsu <hsu@freebsd.org>. + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_mutexattr_init, pthread_mutexattr_init); + +int +_pthread_mutexattr_init(pthread_mutexattr_t *attr) +{ + int ret; + pthread_mutexattr_t pattr; + + if ((pattr = (pthread_mutexattr_t) + malloc(sizeof(struct pthread_mutex_attr))) == NULL) { + ret = ENOMEM; + } else { + memcpy(pattr, &pthread_mutexattr_default, + sizeof(struct pthread_mutex_attr)); + *attr = pattr; + ret = 0; + } + return(ret); +} diff --git a/lib/libc_r/uthread/uthread_mattr_kind_np.c b/lib/libc_r/uthread/uthread_mattr_kind_np.c new file mode 100644 index 0000000..04db2a0 --- /dev/null +++ b/lib/libc_r/uthread/uthread_mattr_kind_np.c @@ -0,0 +1,97 @@ +/* + * Copyright (c) 1996 Jeffrey Hsu <hsu@freebsd.org>. + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_mutexattr_setkind_np, pthread_mutexattr_setkind_np); +__weak_reference(_pthread_mutexattr_getkind_np, pthread_mutexattr_getkind_np); +__weak_reference(_pthread_mutexattr_gettype, pthread_mutexattr_gettype); +__weak_reference(_pthread_mutexattr_settype, pthread_mutexattr_settype); + +int +_pthread_mutexattr_setkind_np(pthread_mutexattr_t *attr, int kind) +{ + int ret; + if (attr == NULL || *attr == NULL) { + errno = EINVAL; + ret = -1; + } else { + (*attr)->m_type = kind; + ret = 0; + } + return(ret); +} + +int +_pthread_mutexattr_getkind_np(pthread_mutexattr_t attr) +{ + int ret; + if (attr == NULL) { + errno = EINVAL; + ret = -1; + } else { + ret = attr->m_type; + } + return(ret); +} + +int +_pthread_mutexattr_settype(pthread_mutexattr_t *attr, int type) +{ + int ret; + if (attr == NULL || *attr == NULL || type >= MUTEX_TYPE_MAX) { + errno = EINVAL; + ret = -1; + } else { + (*attr)->m_type = type; + ret = 0; + } + return(ret); +} + +int +_pthread_mutexattr_gettype(pthread_mutexattr_t *attr, int *type) +{ + int ret; + + if (attr == NULL || *attr == NULL || (*attr)->m_type >= + MUTEX_TYPE_MAX) { + ret = EINVAL; + } else { + *type = (*attr)->m_type; + ret = 0; + } + return ret; +} diff --git a/lib/libc_r/uthread/uthread_msync.c b/lib/libc_r/uthread/uthread_msync.c new file mode 100644 index 0000000..24cbaa6 --- /dev/null +++ b/lib/libc_r/uthread/uthread_msync.c @@ -0,0 +1,42 @@ +/* + * David Leonard <d@openbsd.org>, 1999. Public Domain. + * + * $OpenBSD: uthread_msync.c,v 1.2 1999/06/09 07:16:17 d Exp $ + * + * $FreeBSD$ + */ + +#include <sys/types.h> +#include <sys/mman.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(__msync, msync); + +int +_msync(void *addr, size_t len, int flags) +{ + int ret; + + ret = __sys_msync(addr, len, flags); + + return (ret); +} + +int +__msync(void *addr, size_t len, int flags) +{ + int ret; + + /* + * XXX This is quite pointless unless we know how to get the + * file descriptor associated with the memory, and lock it for + * write. The only real use of this wrapper is to guarantee + * a cancellation point, as per the standard. sigh. + */ + _thread_enter_cancellation_point(); + ret = _msync(addr, len, flags); + _thread_leave_cancellation_point(); + + return ret; +} diff --git a/lib/libc_r/uthread/uthread_multi_np.c b/lib/libc_r/uthread/uthread_multi_np.c new file mode 100644 index 0000000..c1a069f --- /dev/null +++ b/lib/libc_r/uthread/uthread_multi_np.c @@ -0,0 +1,46 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <string.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_multi_np, pthread_multi_np); + +int +_pthread_multi_np() +{ + /* Return to multi-threaded scheduling mode: */ + _thread_single = NULL; + return(0); +} diff --git a/lib/libc_r/uthread/uthread_mutex.c b/lib/libc_r/uthread/uthread_mutex.c new file mode 100644 index 0000000..0f67b4b --- /dev/null +++ b/lib/libc_r/uthread/uthread_mutex.c @@ -0,0 +1,1576 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <stdlib.h> +#include <errno.h> +#include <string.h> +#include <sys/param.h> +#include <sys/queue.h> +#include <pthread.h> +#include "pthread_private.h" + +#if defined(_PTHREADS_INVARIANTS) +#define _MUTEX_INIT_LINK(m) do { \ + (m)->m_qe.tqe_prev = NULL; \ + (m)->m_qe.tqe_next = NULL; \ +} while (0) +#define _MUTEX_ASSERT_IS_OWNED(m) do { \ + if ((m)->m_qe.tqe_prev == NULL) \ + PANIC("mutex is not on list"); \ +} while (0) +#define _MUTEX_ASSERT_NOT_OWNED(m) do { \ + if (((m)->m_qe.tqe_prev != NULL) || \ + ((m)->m_qe.tqe_next != NULL)) \ + PANIC("mutex is on list"); \ +} while (0) +#else +#define _MUTEX_INIT_LINK(m) +#define _MUTEX_ASSERT_IS_OWNED(m) +#define _MUTEX_ASSERT_NOT_OWNED(m) +#endif + +/* + * Prototypes + */ +static inline int mutex_self_trylock(pthread_mutex_t); +static inline int mutex_self_lock(pthread_mutex_t); +static inline int mutex_unlock_common(pthread_mutex_t *, int); +static void mutex_priority_adjust(pthread_mutex_t); +static void mutex_rescan_owned (pthread_t, pthread_mutex_t); +static inline pthread_t mutex_queue_deq(pthread_mutex_t); +static inline void mutex_queue_remove(pthread_mutex_t, pthread_t); +static inline void mutex_queue_enq(pthread_mutex_t, pthread_t); + + +static spinlock_t static_init_lock = _SPINLOCK_INITIALIZER; + +static struct pthread_mutex_attr static_mutex_attr = + PTHREAD_MUTEXATTR_STATIC_INITIALIZER; +static pthread_mutexattr_t static_mattr = &static_mutex_attr; + +/* Single underscore versions provided for libc internal usage: */ +__weak_reference(__pthread_mutex_trylock, pthread_mutex_trylock); +__weak_reference(__pthread_mutex_lock, pthread_mutex_lock); + +/* No difference between libc and application usage of these: */ +__weak_reference(_pthread_mutex_init, pthread_mutex_init); +__weak_reference(_pthread_mutex_destroy, pthread_mutex_destroy); +__weak_reference(_pthread_mutex_unlock, pthread_mutex_unlock); + + +/* Reinitialize a mutex to defaults. */ +int +_mutex_reinit(pthread_mutex_t * mutex) +{ + int ret = 0; + + if (mutex == NULL) + ret = EINVAL; + else if (*mutex == NULL) + ret = pthread_mutex_init(mutex, NULL); + else { + /* + * Initialize the mutex structure: + */ + (*mutex)->m_type = PTHREAD_MUTEX_DEFAULT; + (*mutex)->m_protocol = PTHREAD_PRIO_NONE; + TAILQ_INIT(&(*mutex)->m_queue); + (*mutex)->m_owner = NULL; + (*mutex)->m_data.m_count = 0; + (*mutex)->m_flags &= MUTEX_FLAGS_PRIVATE; + (*mutex)->m_flags |= MUTEX_FLAGS_INITED; + (*mutex)->m_refcount = 0; + (*mutex)->m_prio = 0; + (*mutex)->m_saved_prio = 0; + _MUTEX_INIT_LINK(*mutex); + memset(&(*mutex)->lock, 0, sizeof((*mutex)->lock)); + } + return (ret); +} + +int +_pthread_mutex_init(pthread_mutex_t * mutex, + const pthread_mutexattr_t * mutex_attr) +{ + enum pthread_mutextype type; + int protocol; + int ceiling; + int flags; + pthread_mutex_t pmutex; + int ret = 0; + + if (mutex == NULL) + ret = EINVAL; + + /* Check if default mutex attributes: */ + else if (mutex_attr == NULL || *mutex_attr == NULL) { + /* Default to a (error checking) POSIX mutex: */ + type = PTHREAD_MUTEX_ERRORCHECK; + protocol = PTHREAD_PRIO_NONE; + ceiling = PTHREAD_MAX_PRIORITY; + flags = 0; + } + + /* Check mutex type: */ + else if (((*mutex_attr)->m_type < PTHREAD_MUTEX_ERRORCHECK) || + ((*mutex_attr)->m_type >= MUTEX_TYPE_MAX)) + /* Return an invalid argument error: */ + ret = EINVAL; + + /* Check mutex protocol: */ + else if (((*mutex_attr)->m_protocol < PTHREAD_PRIO_NONE) || + ((*mutex_attr)->m_protocol > PTHREAD_MUTEX_RECURSIVE)) + /* Return an invalid argument error: */ + ret = EINVAL; + + else { + /* Use the requested mutex type and protocol: */ + type = (*mutex_attr)->m_type; + protocol = (*mutex_attr)->m_protocol; + ceiling = (*mutex_attr)->m_ceiling; + flags = (*mutex_attr)->m_flags; + } + + /* Check no errors so far: */ + if (ret == 0) { + if ((pmutex = (pthread_mutex_t) + malloc(sizeof(struct pthread_mutex))) == NULL) + ret = ENOMEM; + else { + /* Set the mutex flags: */ + pmutex->m_flags = flags; + + /* Process according to mutex type: */ + switch (type) { + /* case PTHREAD_MUTEX_DEFAULT: */ + case PTHREAD_MUTEX_ERRORCHECK: + case PTHREAD_MUTEX_NORMAL: + /* Nothing to do here. */ + break; + + /* Single UNIX Spec 2 recursive mutex: */ + case PTHREAD_MUTEX_RECURSIVE: + /* Reset the mutex count: */ + pmutex->m_data.m_count = 0; + break; + + /* Trap invalid mutex types: */ + default: + /* Return an invalid argument error: */ + ret = EINVAL; + break; + } + if (ret == 0) { + /* Initialise the rest of the mutex: */ + TAILQ_INIT(&pmutex->m_queue); + pmutex->m_flags |= MUTEX_FLAGS_INITED; + pmutex->m_owner = NULL; + pmutex->m_type = type; + pmutex->m_protocol = protocol; + pmutex->m_refcount = 0; + if (protocol == PTHREAD_PRIO_PROTECT) + pmutex->m_prio = ceiling; + else + pmutex->m_prio = 0; + pmutex->m_saved_prio = 0; + _MUTEX_INIT_LINK(pmutex); + memset(&pmutex->lock, 0, sizeof(pmutex->lock)); + *mutex = pmutex; + } else { + free(pmutex); + *mutex = NULL; + } + } + } + /* Return the completion status: */ + return(ret); +} + +int +_pthread_mutex_destroy(pthread_mutex_t * mutex) +{ + int ret = 0; + + if (mutex == NULL || *mutex == NULL) + ret = EINVAL; + else { + /* Lock the mutex structure: */ + _SPINLOCK(&(*mutex)->lock); + + /* + * Check to see if this mutex is in use: + */ + if (((*mutex)->m_owner != NULL) || + (TAILQ_FIRST(&(*mutex)->m_queue) != NULL) || + ((*mutex)->m_refcount != 0)) { + ret = EBUSY; + + /* Unlock the mutex structure: */ + _SPINUNLOCK(&(*mutex)->lock); + } + else { + /* + * Free the memory allocated for the mutex + * structure: + */ + _MUTEX_ASSERT_NOT_OWNED(*mutex); + free(*mutex); + + /* + * Leave the caller's pointer NULL now that + * the mutex has been destroyed: + */ + *mutex = NULL; + } + } + + /* Return the completion status: */ + return (ret); +} + +static int +init_static(pthread_mutex_t *mutex) +{ + int ret; + + _SPINLOCK(&static_init_lock); + + if (*mutex == NULL) + ret = pthread_mutex_init(mutex, NULL); + else + ret = 0; + + _SPINUNLOCK(&static_init_lock); + + return(ret); +} + +static int +init_static_private(pthread_mutex_t *mutex) +{ + int ret; + + _SPINLOCK(&static_init_lock); + + if (*mutex == NULL) + ret = pthread_mutex_init(mutex, &static_mattr); + else + ret = 0; + + _SPINUNLOCK(&static_init_lock); + + return(ret); +} + +static int +mutex_trylock_common(pthread_mutex_t *mutex) +{ + struct pthread *curthread = _get_curthread(); + int ret = 0; + + PTHREAD_ASSERT((mutex != NULL) && (*mutex != NULL), + "Uninitialized mutex in pthread_mutex_trylock_basic"); + + /* + * Defer signals to protect the scheduling queues from + * access by the signal handler: + */ + _thread_kern_sig_defer(); + + /* Lock the mutex structure: */ + _SPINLOCK(&(*mutex)->lock); + + /* + * If the mutex was statically allocated, properly + * initialize the tail queue. + */ + if (((*mutex)->m_flags & MUTEX_FLAGS_INITED) == 0) { + TAILQ_INIT(&(*mutex)->m_queue); + _MUTEX_INIT_LINK(*mutex); + (*mutex)->m_flags |= MUTEX_FLAGS_INITED; + } + + /* Process according to mutex type: */ + switch ((*mutex)->m_protocol) { + /* Default POSIX mutex: */ + case PTHREAD_PRIO_NONE: + /* Check if this mutex is not locked: */ + if ((*mutex)->m_owner == NULL) { + /* Lock the mutex for the running thread: */ + (*mutex)->m_owner = curthread; + + /* Add to the list of owned mutexes: */ + _MUTEX_ASSERT_NOT_OWNED(*mutex); + TAILQ_INSERT_TAIL(&curthread->mutexq, + (*mutex), m_qe); + } else if ((*mutex)->m_owner == curthread) + ret = mutex_self_trylock(*mutex); + else + /* Return a busy error: */ + ret = EBUSY; + break; + + /* POSIX priority inheritence mutex: */ + case PTHREAD_PRIO_INHERIT: + /* Check if this mutex is not locked: */ + if ((*mutex)->m_owner == NULL) { + /* Lock the mutex for the running thread: */ + (*mutex)->m_owner = curthread; + + /* Track number of priority mutexes owned: */ + curthread->priority_mutex_count++; + + /* + * The mutex takes on the attributes of the + * running thread when there are no waiters. + */ + (*mutex)->m_prio = curthread->active_priority; + (*mutex)->m_saved_prio = + curthread->inherited_priority; + + /* Add to the list of owned mutexes: */ + _MUTEX_ASSERT_NOT_OWNED(*mutex); + TAILQ_INSERT_TAIL(&curthread->mutexq, + (*mutex), m_qe); + } else if ((*mutex)->m_owner == curthread) + ret = mutex_self_trylock(*mutex); + else + /* Return a busy error: */ + ret = EBUSY; + break; + + /* POSIX priority protection mutex: */ + case PTHREAD_PRIO_PROTECT: + /* Check for a priority ceiling violation: */ + if (curthread->active_priority > (*mutex)->m_prio) + ret = EINVAL; + + /* Check if this mutex is not locked: */ + else if ((*mutex)->m_owner == NULL) { + /* Lock the mutex for the running thread: */ + (*mutex)->m_owner = curthread; + + /* Track number of priority mutexes owned: */ + curthread->priority_mutex_count++; + + /* + * The running thread inherits the ceiling + * priority of the mutex and executes at that + * priority. + */ + curthread->active_priority = (*mutex)->m_prio; + (*mutex)->m_saved_prio = + curthread->inherited_priority; + curthread->inherited_priority = + (*mutex)->m_prio; + + /* Add to the list of owned mutexes: */ + _MUTEX_ASSERT_NOT_OWNED(*mutex); + TAILQ_INSERT_TAIL(&curthread->mutexq, + (*mutex), m_qe); + } else if ((*mutex)->m_owner == curthread) + ret = mutex_self_trylock(*mutex); + else + /* Return a busy error: */ + ret = EBUSY; + break; + + /* Trap invalid mutex types: */ + default: + /* Return an invalid argument error: */ + ret = EINVAL; + break; + } + + /* Unlock the mutex structure: */ + _SPINUNLOCK(&(*mutex)->lock); + + /* + * Undefer and handle pending signals, yielding if + * necessary: + */ + _thread_kern_sig_undefer(); + + /* Return the completion status: */ + return (ret); +} + +int +__pthread_mutex_trylock(pthread_mutex_t *mutex) +{ + int ret = 0; + + if (mutex == NULL) + ret = EINVAL; + + /* + * If the mutex is statically initialized, perform the dynamic + * initialization: + */ + else if ((*mutex != NULL) || (ret = init_static(mutex)) == 0) + ret = mutex_trylock_common(mutex); + + return (ret); +} + +int +_pthread_mutex_trylock(pthread_mutex_t *mutex) +{ + int ret = 0; + + if (mutex == NULL) + ret = EINVAL; + + /* + * If the mutex is statically initialized, perform the dynamic + * initialization marking the mutex private (delete safe): + */ + else if ((*mutex != NULL) || (ret = init_static_private(mutex)) == 0) + ret = mutex_trylock_common(mutex); + + return (ret); +} + +static int +mutex_lock_common(pthread_mutex_t * mutex) +{ + struct pthread *curthread = _get_curthread(); + int ret = 0; + + PTHREAD_ASSERT((mutex != NULL) && (*mutex != NULL), + "Uninitialized mutex in pthread_mutex_trylock_basic"); + + /* Reset the interrupted flag: */ + curthread->interrupted = 0; + + /* + * Enter a loop waiting to become the mutex owner. We need a + * loop in case the waiting thread is interrupted by a signal + * to execute a signal handler. It is not (currently) possible + * to remain in the waiting queue while running a handler. + * Instead, the thread is interrupted and backed out of the + * waiting queue prior to executing the signal handler. + */ + do { + /* + * Defer signals to protect the scheduling queues from + * access by the signal handler: + */ + _thread_kern_sig_defer(); + + /* Lock the mutex structure: */ + _SPINLOCK(&(*mutex)->lock); + + /* + * If the mutex was statically allocated, properly + * initialize the tail queue. + */ + if (((*mutex)->m_flags & MUTEX_FLAGS_INITED) == 0) { + TAILQ_INIT(&(*mutex)->m_queue); + (*mutex)->m_flags |= MUTEX_FLAGS_INITED; + _MUTEX_INIT_LINK(*mutex); + } + + /* Process according to mutex type: */ + switch ((*mutex)->m_protocol) { + /* Default POSIX mutex: */ + case PTHREAD_PRIO_NONE: + if ((*mutex)->m_owner == NULL) { + /* Lock the mutex for this thread: */ + (*mutex)->m_owner = curthread; + + /* Add to the list of owned mutexes: */ + _MUTEX_ASSERT_NOT_OWNED(*mutex); + TAILQ_INSERT_TAIL(&curthread->mutexq, + (*mutex), m_qe); + + } else if ((*mutex)->m_owner == curthread) + ret = mutex_self_lock(*mutex); + else { + /* + * Join the queue of threads waiting to lock + * the mutex: + */ + mutex_queue_enq(*mutex, curthread); + + /* + * Keep a pointer to the mutex this thread + * is waiting on: + */ + curthread->data.mutex = *mutex; + + /* + * Unlock the mutex structure and schedule the + * next thread: + */ + _thread_kern_sched_state_unlock(PS_MUTEX_WAIT, + &(*mutex)->lock, __FILE__, __LINE__); + + /* Lock the mutex structure again: */ + _SPINLOCK(&(*mutex)->lock); + } + break; + + /* POSIX priority inheritence mutex: */ + case PTHREAD_PRIO_INHERIT: + /* Check if this mutex is not locked: */ + if ((*mutex)->m_owner == NULL) { + /* Lock the mutex for this thread: */ + (*mutex)->m_owner = curthread; + + /* Track number of priority mutexes owned: */ + curthread->priority_mutex_count++; + + /* + * The mutex takes on attributes of the + * running thread when there are no waiters. + */ + (*mutex)->m_prio = curthread->active_priority; + (*mutex)->m_saved_prio = + curthread->inherited_priority; + curthread->inherited_priority = + (*mutex)->m_prio; + + /* Add to the list of owned mutexes: */ + _MUTEX_ASSERT_NOT_OWNED(*mutex); + TAILQ_INSERT_TAIL(&curthread->mutexq, + (*mutex), m_qe); + + } else if ((*mutex)->m_owner == curthread) + ret = mutex_self_lock(*mutex); + else { + /* + * Join the queue of threads waiting to lock + * the mutex: + */ + mutex_queue_enq(*mutex, curthread); + + /* + * Keep a pointer to the mutex this thread + * is waiting on: + */ + curthread->data.mutex = *mutex; + + if (curthread->active_priority > + (*mutex)->m_prio) + /* Adjust priorities: */ + mutex_priority_adjust(*mutex); + + /* + * Unlock the mutex structure and schedule the + * next thread: + */ + _thread_kern_sched_state_unlock(PS_MUTEX_WAIT, + &(*mutex)->lock, __FILE__, __LINE__); + + /* Lock the mutex structure again: */ + _SPINLOCK(&(*mutex)->lock); + } + break; + + /* POSIX priority protection mutex: */ + case PTHREAD_PRIO_PROTECT: + /* Check for a priority ceiling violation: */ + if (curthread->active_priority > (*mutex)->m_prio) + ret = EINVAL; + + /* Check if this mutex is not locked: */ + else if ((*mutex)->m_owner == NULL) { + /* + * Lock the mutex for the running + * thread: + */ + (*mutex)->m_owner = curthread; + + /* Track number of priority mutexes owned: */ + curthread->priority_mutex_count++; + + /* + * The running thread inherits the ceiling + * priority of the mutex and executes at that + * priority: + */ + curthread->active_priority = (*mutex)->m_prio; + (*mutex)->m_saved_prio = + curthread->inherited_priority; + curthread->inherited_priority = + (*mutex)->m_prio; + + /* Add to the list of owned mutexes: */ + _MUTEX_ASSERT_NOT_OWNED(*mutex); + TAILQ_INSERT_TAIL(&curthread->mutexq, + (*mutex), m_qe); + } else if ((*mutex)->m_owner == curthread) + ret = mutex_self_lock(*mutex); + else { + /* + * Join the queue of threads waiting to lock + * the mutex: + */ + mutex_queue_enq(*mutex, curthread); + + /* + * Keep a pointer to the mutex this thread + * is waiting on: + */ + curthread->data.mutex = *mutex; + + /* Clear any previous error: */ + curthread->error = 0; + + /* + * Unlock the mutex structure and schedule the + * next thread: + */ + _thread_kern_sched_state_unlock(PS_MUTEX_WAIT, + &(*mutex)->lock, __FILE__, __LINE__); + + /* Lock the mutex structure again: */ + _SPINLOCK(&(*mutex)->lock); + + /* + * The threads priority may have changed while + * waiting for the mutex causing a ceiling + * violation. + */ + ret = curthread->error; + curthread->error = 0; + } + break; + + /* Trap invalid mutex types: */ + default: + /* Return an invalid argument error: */ + ret = EINVAL; + break; + } + + /* + * Check to see if this thread was interrupted and + * is still in the mutex queue of waiting threads: + */ + if (curthread->interrupted != 0) + mutex_queue_remove(*mutex, curthread); + + /* Unlock the mutex structure: */ + _SPINUNLOCK(&(*mutex)->lock); + + /* + * Undefer and handle pending signals, yielding if + * necessary: + */ + _thread_kern_sig_undefer(); + } while (((*mutex)->m_owner != curthread) && (ret == 0) && + (curthread->interrupted == 0)); + + if (curthread->interrupted != 0 && + curthread->continuation != NULL) + curthread->continuation((void *) curthread); + + /* Return the completion status: */ + return (ret); +} + +int +__pthread_mutex_lock(pthread_mutex_t *mutex) +{ + int ret = 0; + + if (_thread_initial == NULL) + _thread_init(); + + if (mutex == NULL) + ret = EINVAL; + + /* + * If the mutex is statically initialized, perform the dynamic + * initialization: + */ + else if ((*mutex != NULL) || ((ret = init_static(mutex)) == 0)) + ret = mutex_lock_common(mutex); + + return (ret); +} + +int +_pthread_mutex_lock(pthread_mutex_t *mutex) +{ + int ret = 0; + + if (_thread_initial == NULL) + _thread_init(); + + if (mutex == NULL) + ret = EINVAL; + + /* + * If the mutex is statically initialized, perform the dynamic + * initialization marking it private (delete safe): + */ + else if ((*mutex != NULL) || ((ret = init_static_private(mutex)) == 0)) + ret = mutex_lock_common(mutex); + + return (ret); +} + +int +_pthread_mutex_unlock(pthread_mutex_t * mutex) +{ + return (mutex_unlock_common(mutex, /* add reference */ 0)); +} + +int +_mutex_cv_unlock(pthread_mutex_t * mutex) +{ + return (mutex_unlock_common(mutex, /* add reference */ 1)); +} + +int +_mutex_cv_lock(pthread_mutex_t * mutex) +{ + int ret; + if ((ret = pthread_mutex_lock(mutex)) == 0) + (*mutex)->m_refcount--; + return (ret); +} + +static inline int +mutex_self_trylock(pthread_mutex_t mutex) +{ + int ret = 0; + + switch (mutex->m_type) { + + /* case PTHREAD_MUTEX_DEFAULT: */ + case PTHREAD_MUTEX_ERRORCHECK: + case PTHREAD_MUTEX_NORMAL: + /* + * POSIX specifies that mutexes should return EDEADLK if a + * recursive lock is detected. + */ + ret = EBUSY; + break; + + case PTHREAD_MUTEX_RECURSIVE: + /* Increment the lock count: */ + mutex->m_data.m_count++; + break; + + default: + /* Trap invalid mutex types; */ + ret = EINVAL; + } + + return(ret); +} + +static inline int +mutex_self_lock(pthread_mutex_t mutex) +{ + int ret = 0; + + switch (mutex->m_type) { + /* case PTHREAD_MUTEX_DEFAULT: */ + case PTHREAD_MUTEX_ERRORCHECK: + /* + * POSIX specifies that mutexes should return EDEADLK if a + * recursive lock is detected. + */ + ret = EDEADLK; + break; + + case PTHREAD_MUTEX_NORMAL: + /* + * What SS2 define as a 'normal' mutex. Intentionally + * deadlock on attempts to get a lock you already own. + */ + _thread_kern_sched_state_unlock(PS_DEADLOCK, + &mutex->lock, __FILE__, __LINE__); + break; + + case PTHREAD_MUTEX_RECURSIVE: + /* Increment the lock count: */ + mutex->m_data.m_count++; + break; + + default: + /* Trap invalid mutex types; */ + ret = EINVAL; + } + + return(ret); +} + +static inline int +mutex_unlock_common(pthread_mutex_t * mutex, int add_reference) +{ + struct pthread *curthread = _get_curthread(); + int ret = 0; + + if (mutex == NULL || *mutex == NULL) { + ret = EINVAL; + } else { + /* + * Defer signals to protect the scheduling queues from + * access by the signal handler: + */ + _thread_kern_sig_defer(); + + /* Lock the mutex structure: */ + _SPINLOCK(&(*mutex)->lock); + + /* Process according to mutex type: */ + switch ((*mutex)->m_protocol) { + /* Default POSIX mutex: */ + case PTHREAD_PRIO_NONE: + /* + * Check if the running thread is not the owner of the + * mutex: + */ + if ((*mutex)->m_owner != curthread) { + /* + * Return an invalid argument error for no + * owner and a permission error otherwise: + */ + ret = (*mutex)->m_owner == NULL ? EINVAL : EPERM; + } + else if (((*mutex)->m_type == PTHREAD_MUTEX_RECURSIVE) && + ((*mutex)->m_data.m_count > 0)) { + /* Decrement the count: */ + (*mutex)->m_data.m_count--; + } else { + /* + * Clear the count in case this is recursive + * mutex. + */ + (*mutex)->m_data.m_count = 0; + + /* Remove the mutex from the threads queue. */ + _MUTEX_ASSERT_IS_OWNED(*mutex); + TAILQ_REMOVE(&(*mutex)->m_owner->mutexq, + (*mutex), m_qe); + _MUTEX_INIT_LINK(*mutex); + + /* + * Get the next thread from the queue of + * threads waiting on the mutex: + */ + if (((*mutex)->m_owner = + mutex_queue_deq(*mutex)) != NULL) { + /* + * Unless the new owner of the mutex is + * currently suspended, allow the owner + * to run. If the thread is suspended, + * make a note that the thread isn't in + * a wait queue any more. + */ + if (((*mutex)->m_owner->state != + PS_SUSPENDED)) { + PTHREAD_NEW_STATE((*mutex)->m_owner, + PS_RUNNING); + } else { + (*mutex)->m_owner->suspended = + SUSP_NOWAIT; + } + + /* + * Add the mutex to the threads list of + * owned mutexes: + */ + TAILQ_INSERT_TAIL(&(*mutex)->m_owner->mutexq, + (*mutex), m_qe); + + /* + * The owner is no longer waiting for + * this mutex: + */ + (*mutex)->m_owner->data.mutex = NULL; + } + } + break; + + /* POSIX priority inheritence mutex: */ + case PTHREAD_PRIO_INHERIT: + /* + * Check if the running thread is not the owner of the + * mutex: + */ + if ((*mutex)->m_owner != curthread) { + /* + * Return an invalid argument error for no + * owner and a permission error otherwise: + */ + ret = (*mutex)->m_owner == NULL ? EINVAL : EPERM; + } + else if (((*mutex)->m_type == PTHREAD_MUTEX_RECURSIVE) && + ((*mutex)->m_data.m_count > 0)) { + /* Decrement the count: */ + (*mutex)->m_data.m_count--; + } else { + /* + * Clear the count in case this is recursive + * mutex. + */ + (*mutex)->m_data.m_count = 0; + + /* + * Restore the threads inherited priority and + * recompute the active priority (being careful + * not to override changes in the threads base + * priority subsequent to locking the mutex). + */ + curthread->inherited_priority = + (*mutex)->m_saved_prio; + curthread->active_priority = + MAX(curthread->inherited_priority, + curthread->base_priority); + + /* + * This thread now owns one less priority mutex. + */ + curthread->priority_mutex_count--; + + /* Remove the mutex from the threads queue. */ + _MUTEX_ASSERT_IS_OWNED(*mutex); + TAILQ_REMOVE(&(*mutex)->m_owner->mutexq, + (*mutex), m_qe); + _MUTEX_INIT_LINK(*mutex); + + /* + * Get the next thread from the queue of threads + * waiting on the mutex: + */ + if (((*mutex)->m_owner = + mutex_queue_deq(*mutex)) == NULL) + /* This mutex has no priority. */ + (*mutex)->m_prio = 0; + else { + /* + * Track number of priority mutexes owned: + */ + (*mutex)->m_owner->priority_mutex_count++; + + /* + * Add the mutex to the threads list + * of owned mutexes: + */ + TAILQ_INSERT_TAIL(&(*mutex)->m_owner->mutexq, + (*mutex), m_qe); + + /* + * The owner is no longer waiting for + * this mutex: + */ + (*mutex)->m_owner->data.mutex = NULL; + + /* + * Set the priority of the mutex. Since + * our waiting threads are in descending + * priority order, the priority of the + * mutex becomes the active priority of + * the thread we just dequeued. + */ + (*mutex)->m_prio = + (*mutex)->m_owner->active_priority; + + /* + * Save the owning threads inherited + * priority: + */ + (*mutex)->m_saved_prio = + (*mutex)->m_owner->inherited_priority; + + /* + * The owning threads inherited priority + * now becomes his active priority (the + * priority of the mutex). + */ + (*mutex)->m_owner->inherited_priority = + (*mutex)->m_prio; + + /* + * Unless the new owner of the mutex is + * currently suspended, allow the owner + * to run. If the thread is suspended, + * make a note that the thread isn't in + * a wait queue any more. + */ + if (((*mutex)->m_owner->state != + PS_SUSPENDED)) { + PTHREAD_NEW_STATE((*mutex)->m_owner, + PS_RUNNING); + } else { + (*mutex)->m_owner->suspended = + SUSP_NOWAIT; + } + } + } + break; + + /* POSIX priority ceiling mutex: */ + case PTHREAD_PRIO_PROTECT: + /* + * Check if the running thread is not the owner of the + * mutex: + */ + if ((*mutex)->m_owner != curthread) { + /* + * Return an invalid argument error for no + * owner and a permission error otherwise: + */ + ret = (*mutex)->m_owner == NULL ? EINVAL : EPERM; + } + else if (((*mutex)->m_type == PTHREAD_MUTEX_RECURSIVE) && + ((*mutex)->m_data.m_count > 0)) { + /* Decrement the count: */ + (*mutex)->m_data.m_count--; + } else { + /* + * Clear the count in case this is recursive + * mutex. + */ + (*mutex)->m_data.m_count = 0; + + /* + * Restore the threads inherited priority and + * recompute the active priority (being careful + * not to override changes in the threads base + * priority subsequent to locking the mutex). + */ + curthread->inherited_priority = + (*mutex)->m_saved_prio; + curthread->active_priority = + MAX(curthread->inherited_priority, + curthread->base_priority); + + /* + * This thread now owns one less priority mutex. + */ + curthread->priority_mutex_count--; + + /* Remove the mutex from the threads queue. */ + _MUTEX_ASSERT_IS_OWNED(*mutex); + TAILQ_REMOVE(&(*mutex)->m_owner->mutexq, + (*mutex), m_qe); + _MUTEX_INIT_LINK(*mutex); + + /* + * Enter a loop to find a waiting thread whose + * active priority will not cause a ceiling + * violation: + */ + while ((((*mutex)->m_owner = + mutex_queue_deq(*mutex)) != NULL) && + ((*mutex)->m_owner->active_priority > + (*mutex)->m_prio)) { + /* + * Either the mutex ceiling priority + * been lowered and/or this threads + * priority has been raised subsequent + * to this thread being queued on the + * waiting list. + */ + (*mutex)->m_owner->error = EINVAL; + PTHREAD_NEW_STATE((*mutex)->m_owner, + PS_RUNNING); + /* + * The thread is no longer waiting for + * this mutex: + */ + (*mutex)->m_owner->data.mutex = NULL; + } + + /* Check for a new owner: */ + if ((*mutex)->m_owner != NULL) { + /* + * Track number of priority mutexes owned: + */ + (*mutex)->m_owner->priority_mutex_count++; + + /* + * Add the mutex to the threads list + * of owned mutexes: + */ + TAILQ_INSERT_TAIL(&(*mutex)->m_owner->mutexq, + (*mutex), m_qe); + + /* + * The owner is no longer waiting for + * this mutex: + */ + (*mutex)->m_owner->data.mutex = NULL; + + /* + * Save the owning threads inherited + * priority: + */ + (*mutex)->m_saved_prio = + (*mutex)->m_owner->inherited_priority; + + /* + * The owning thread inherits the + * ceiling priority of the mutex and + * executes at that priority: + */ + (*mutex)->m_owner->inherited_priority = + (*mutex)->m_prio; + (*mutex)->m_owner->active_priority = + (*mutex)->m_prio; + + /* + * Unless the new owner of the mutex is + * currently suspended, allow the owner + * to run. If the thread is suspended, + * make a note that the thread isn't in + * a wait queue any more. + */ + if (((*mutex)->m_owner->state != + PS_SUSPENDED)) { + PTHREAD_NEW_STATE((*mutex)->m_owner, + PS_RUNNING); + } else { + (*mutex)->m_owner->suspended = + SUSP_NOWAIT; + } + } + } + break; + + /* Trap invalid mutex types: */ + default: + /* Return an invalid argument error: */ + ret = EINVAL; + break; + } + + if ((ret == 0) && (add_reference != 0)) { + /* Increment the reference count: */ + (*mutex)->m_refcount++; + } + + /* Unlock the mutex structure: */ + _SPINUNLOCK(&(*mutex)->lock); + + /* + * Undefer and handle pending signals, yielding if + * necessary: + */ + _thread_kern_sig_undefer(); + } + + /* Return the completion status: */ + return (ret); +} + + +/* + * This function is called when a change in base priority occurs for + * a thread that is holding or waiting for a priority protection or + * inheritence mutex. A change in a threads base priority can effect + * changes to active priorities of other threads and to the ordering + * of mutex locking by waiting threads. + * + * This must be called while thread scheduling is deferred. + */ +void +_mutex_notify_priochange(pthread_t pthread) +{ + /* Adjust the priorites of any owned priority mutexes: */ + if (pthread->priority_mutex_count > 0) { + /* + * Rescan the mutexes owned by this thread and correct + * their priorities to account for this threads change + * in priority. This has the side effect of changing + * the threads active priority. + */ + mutex_rescan_owned(pthread, /* rescan all owned */ NULL); + } + + /* + * If this thread is waiting on a priority inheritence mutex, + * check for priority adjustments. A change in priority can + * also effect a ceiling violation(*) for a thread waiting on + * a priority protection mutex; we don't perform the check here + * as it is done in pthread_mutex_unlock. + * + * (*) It should be noted that a priority change to a thread + * _after_ taking and owning a priority ceiling mutex + * does not affect ownership of that mutex; the ceiling + * priority is only checked before mutex ownership occurs. + */ + if (pthread->state == PS_MUTEX_WAIT) { + /* Lock the mutex structure: */ + _SPINLOCK(&pthread->data.mutex->lock); + + /* + * Check to make sure this thread is still in the same state + * (the spinlock above can yield the CPU to another thread): + */ + if (pthread->state == PS_MUTEX_WAIT) { + /* + * Remove and reinsert this thread into the list of + * waiting threads to preserve decreasing priority + * order. + */ + mutex_queue_remove(pthread->data.mutex, pthread); + mutex_queue_enq(pthread->data.mutex, pthread); + + if (pthread->data.mutex->m_protocol == + PTHREAD_PRIO_INHERIT) { + /* Adjust priorities: */ + mutex_priority_adjust(pthread->data.mutex); + } + } + + /* Unlock the mutex structure: */ + _SPINUNLOCK(&pthread->data.mutex->lock); + } +} + +/* + * Called when a new thread is added to the mutex waiting queue or + * when a threads priority changes that is already in the mutex + * waiting queue. + */ +static void +mutex_priority_adjust(pthread_mutex_t mutex) +{ + pthread_t pthread_next, pthread = mutex->m_owner; + int temp_prio; + pthread_mutex_t m = mutex; + + /* + * Calculate the mutex priority as the maximum of the highest + * active priority of any waiting threads and the owning threads + * active priority(*). + * + * (*) Because the owning threads current active priority may + * reflect priority inherited from this mutex (and the mutex + * priority may have changed) we must recalculate the active + * priority based on the threads saved inherited priority + * and its base priority. + */ + pthread_next = TAILQ_FIRST(&m->m_queue); /* should never be NULL */ + temp_prio = MAX(pthread_next->active_priority, + MAX(m->m_saved_prio, pthread->base_priority)); + + /* See if this mutex really needs adjusting: */ + if (temp_prio == m->m_prio) + /* No need to propagate the priority: */ + return; + + /* Set new priority of the mutex: */ + m->m_prio = temp_prio; + + while (m != NULL) { + /* + * Save the threads priority before rescanning the + * owned mutexes: + */ + temp_prio = pthread->active_priority; + + /* + * Fix the priorities for all the mutexes this thread has + * locked since taking this mutex. This also has a + * potential side-effect of changing the threads priority. + */ + mutex_rescan_owned(pthread, m); + + /* + * If the thread is currently waiting on a mutex, check + * to see if the threads new priority has affected the + * priority of the mutex. + */ + if ((temp_prio != pthread->active_priority) && + (pthread->state == PS_MUTEX_WAIT) && + (pthread->data.mutex->m_protocol == PTHREAD_PRIO_INHERIT)) { + /* Grab the mutex this thread is waiting on: */ + m = pthread->data.mutex; + + /* + * The priority for this thread has changed. Remove + * and reinsert this thread into the list of waiting + * threads to preserve decreasing priority order. + */ + mutex_queue_remove(m, pthread); + mutex_queue_enq(m, pthread); + + /* Grab the waiting thread with highest priority: */ + pthread_next = TAILQ_FIRST(&m->m_queue); + + /* + * Calculate the mutex priority as the maximum of the + * highest active priority of any waiting threads and + * the owning threads active priority. + */ + temp_prio = MAX(pthread_next->active_priority, + MAX(m->m_saved_prio, m->m_owner->base_priority)); + + if (temp_prio != m->m_prio) { + /* + * The priority needs to be propagated to the + * mutex this thread is waiting on and up to + * the owner of that mutex. + */ + m->m_prio = temp_prio; + pthread = m->m_owner; + } + else + /* We're done: */ + m = NULL; + + } + else + /* We're done: */ + m = NULL; + } +} + +static void +mutex_rescan_owned(pthread_t pthread, pthread_mutex_t mutex) +{ + int active_prio, inherited_prio; + pthread_mutex_t m; + pthread_t pthread_next; + + /* + * Start walking the mutexes the thread has taken since + * taking this mutex. + */ + if (mutex == NULL) { + /* + * A null mutex means start at the beginning of the owned + * mutex list. + */ + m = TAILQ_FIRST(&pthread->mutexq); + + /* There is no inherited priority yet. */ + inherited_prio = 0; + } + else { + /* + * The caller wants to start after a specific mutex. It + * is assumed that this mutex is a priority inheritence + * mutex and that its priority has been correctly + * calculated. + */ + m = TAILQ_NEXT(mutex, m_qe); + + /* Start inheriting priority from the specified mutex. */ + inherited_prio = mutex->m_prio; + } + active_prio = MAX(inherited_prio, pthread->base_priority); + + while (m != NULL) { + /* + * We only want to deal with priority inheritence + * mutexes. This might be optimized by only placing + * priority inheritence mutexes into the owned mutex + * list, but it may prove to be useful having all + * owned mutexes in this list. Consider a thread + * exiting while holding mutexes... + */ + if (m->m_protocol == PTHREAD_PRIO_INHERIT) { + /* + * Fix the owners saved (inherited) priority to + * reflect the priority of the previous mutex. + */ + m->m_saved_prio = inherited_prio; + + if ((pthread_next = TAILQ_FIRST(&m->m_queue)) != NULL) + /* Recalculate the priority of the mutex: */ + m->m_prio = MAX(active_prio, + pthread_next->active_priority); + else + m->m_prio = active_prio; + + /* Recalculate new inherited and active priorities: */ + inherited_prio = m->m_prio; + active_prio = MAX(m->m_prio, pthread->base_priority); + } + + /* Advance to the next mutex owned by this thread: */ + m = TAILQ_NEXT(m, m_qe); + } + + /* + * Fix the threads inherited priority and recalculate its + * active priority. + */ + pthread->inherited_priority = inherited_prio; + active_prio = MAX(inherited_prio, pthread->base_priority); + + if (active_prio != pthread->active_priority) { + /* + * If this thread is in the priority queue, it must be + * removed and reinserted for its new priority. + */ + if (pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) { + /* + * Remove the thread from the priority queue + * before changing its priority: + */ + PTHREAD_PRIOQ_REMOVE(pthread); + + /* + * POSIX states that if the priority is being + * lowered, the thread must be inserted at the + * head of the queue for its priority if it owns + * any priority protection or inheritence mutexes. + */ + if ((active_prio < pthread->active_priority) && + (pthread->priority_mutex_count > 0)) { + /* Set the new active priority. */ + pthread->active_priority = active_prio; + + PTHREAD_PRIOQ_INSERT_HEAD(pthread); + } + else { + /* Set the new active priority. */ + pthread->active_priority = active_prio; + + PTHREAD_PRIOQ_INSERT_TAIL(pthread); + } + } + else { + /* Set the new active priority. */ + pthread->active_priority = active_prio; + } + } +} + +void +_mutex_unlock_private(pthread_t pthread) +{ + struct pthread_mutex *m, *m_next; + + for (m = TAILQ_FIRST(&pthread->mutexq); m != NULL; m = m_next) { + m_next = TAILQ_NEXT(m, m_qe); + if ((m->m_flags & MUTEX_FLAGS_PRIVATE) != 0) + pthread_mutex_unlock(&m); + } +} + +void +_mutex_lock_backout(pthread_t pthread) +{ + struct pthread_mutex *mutex; + + /* + * Defer signals to protect the scheduling queues from + * access by the signal handler: + */ + _thread_kern_sig_defer(); + if ((pthread->flags & PTHREAD_FLAGS_IN_MUTEXQ) != 0) { + mutex = pthread->data.mutex; + + /* Lock the mutex structure: */ + _SPINLOCK(&mutex->lock); + + mutex_queue_remove(mutex, pthread); + + /* This thread is no longer waiting for the mutex: */ + pthread->data.mutex = NULL; + + /* Unlock the mutex structure: */ + _SPINUNLOCK(&mutex->lock); + + } + /* + * Undefer and handle pending signals, yielding if + * necessary: + */ + _thread_kern_sig_undefer(); +} + +/* + * Dequeue a waiting thread from the head of a mutex queue in descending + * priority order. + */ +static inline pthread_t +mutex_queue_deq(pthread_mutex_t mutex) +{ + pthread_t pthread; + + while ((pthread = TAILQ_FIRST(&mutex->m_queue)) != NULL) { + TAILQ_REMOVE(&mutex->m_queue, pthread, sqe); + pthread->flags &= ~PTHREAD_FLAGS_IN_MUTEXQ; + + /* + * Only exit the loop if the thread hasn't been + * cancelled. + */ + if (pthread->interrupted == 0) + break; + } + + return(pthread); +} + +/* + * Remove a waiting thread from a mutex queue in descending priority order. + */ +static inline void +mutex_queue_remove(pthread_mutex_t mutex, pthread_t pthread) +{ + if ((pthread->flags & PTHREAD_FLAGS_IN_MUTEXQ) != 0) { + TAILQ_REMOVE(&mutex->m_queue, pthread, sqe); + pthread->flags &= ~PTHREAD_FLAGS_IN_MUTEXQ; + } +} + +/* + * Enqueue a waiting thread to a queue in descending priority order. + */ +static inline void +mutex_queue_enq(pthread_mutex_t mutex, pthread_t pthread) +{ + pthread_t tid = TAILQ_LAST(&mutex->m_queue, mutex_head); + + PTHREAD_ASSERT_NOT_IN_SYNCQ(pthread); + /* + * For the common case of all threads having equal priority, + * we perform a quick check against the priority of the thread + * at the tail of the queue. + */ + if ((tid == NULL) || (pthread->active_priority <= tid->active_priority)) + TAILQ_INSERT_TAIL(&mutex->m_queue, pthread, sqe); + else { + tid = TAILQ_FIRST(&mutex->m_queue); + while (pthread->active_priority <= tid->active_priority) + tid = TAILQ_NEXT(tid, sqe); + TAILQ_INSERT_BEFORE(tid, pthread, sqe); + } + pthread->flags |= PTHREAD_FLAGS_IN_MUTEXQ; +} + diff --git a/lib/libc_r/uthread/uthread_mutex_prioceiling.c b/lib/libc_r/uthread/uthread_mutex_prioceiling.c new file mode 100644 index 0000000..2682abc --- /dev/null +++ b/lib/libc_r/uthread/uthread_mutex_prioceiling.c @@ -0,0 +1,113 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * 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 Daniel Eischen. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_mutexattr_getprioceiling, pthread_mutexattr_getprioceiling); +__weak_reference(_pthread_mutexattr_setprioceiling, pthread_mutexattr_setprioceiling); +__weak_reference(_pthread_mutex_getprioceiling, pthread_mutex_getprioceiling); +__weak_reference(_pthread_mutex_setprioceiling, pthread_mutex_setprioceiling); + +int +_pthread_mutexattr_getprioceiling(pthread_mutexattr_t *mattr, int *prioceiling) +{ + int ret = 0; + + if ((mattr == NULL) || (*mattr == NULL)) + ret = EINVAL; + else if ((*mattr)->m_protocol != PTHREAD_PRIO_PROTECT) + ret = EINVAL; + else + *prioceiling = (*mattr)->m_ceiling; + + return(ret); +} + +int +_pthread_mutexattr_setprioceiling(pthread_mutexattr_t *mattr, int prioceiling) +{ + int ret = 0; + + if ((mattr == NULL) || (*mattr == NULL)) + ret = EINVAL; + else if ((*mattr)->m_protocol != PTHREAD_PRIO_PROTECT) + ret = EINVAL; + else + (*mattr)->m_ceiling = prioceiling; + + return(ret); +} + +int +_pthread_mutex_getprioceiling(pthread_mutex_t *mutex, + int *prioceiling) +{ + int ret; + + if ((mutex == NULL) || (*mutex == NULL)) + ret = EINVAL; + else if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT) + ret = EINVAL; + else + ret = (*mutex)->m_prio; + + return(ret); +} + +int +_pthread_mutex_setprioceiling(pthread_mutex_t *mutex, + int prioceiling, int *old_ceiling) +{ + int ret = 0; + + if ((mutex == NULL) || (*mutex == NULL)) + ret = EINVAL; + else if ((*mutex)->m_protocol != PTHREAD_PRIO_PROTECT) + ret = EINVAL; + else { + /* Lock the mutex: */ + if ((ret = pthread_mutex_lock(mutex)) == 0) { + /* Return the old ceiling and set the new ceiling: */ + *old_ceiling = (*mutex)->m_prio; + (*mutex)->m_prio = prioceiling; + + /* Unlock the mutex: */ + ret = pthread_mutex_unlock(mutex); + } + } + return(ret); +} diff --git a/lib/libc_r/uthread/uthread_mutex_protocol.c b/lib/libc_r/uthread/uthread_mutex_protocol.c new file mode 100644 index 0000000..4d020d6 --- /dev/null +++ b/lib/libc_r/uthread/uthread_mutex_protocol.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * 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 Daniel Eischen. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <string.h> +#include <stdlib.h> +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_mutexattr_getprotocol, pthread_mutexattr_getprotocol); +__weak_reference(_pthread_mutexattr_setprotocol, pthread_mutexattr_setprotocol); + +int +_pthread_mutexattr_getprotocol(pthread_mutexattr_t *mattr, int *protocol) +{ + int ret = 0; + + if ((mattr == NULL) || (*mattr == NULL)) + ret = EINVAL; + else + *protocol = (*mattr)->m_protocol; + + return(ret); +} + +int +_pthread_mutexattr_setprotocol(pthread_mutexattr_t *mattr, int protocol) +{ + int ret = 0; + + if ((mattr == NULL) || (*mattr == NULL) || + (protocol < PTHREAD_PRIO_NONE) || (protocol > PTHREAD_PRIO_PROTECT)) + ret = EINVAL; + else { + (*mattr)->m_protocol = protocol; + (*mattr)->m_ceiling = PTHREAD_MAX_PRIORITY; + } + return(ret); +} + diff --git a/lib/libc_r/uthread/uthread_mutexattr_destroy.c b/lib/libc_r/uthread/uthread_mutexattr_destroy.c new file mode 100644 index 0000000..bdc85a5 --- /dev/null +++ b/lib/libc_r/uthread/uthread_mutexattr_destroy.c @@ -0,0 +1,53 @@ +/* + * Copyright (c) 1997 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <stdlib.h> +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_mutexattr_destroy, pthread_mutexattr_destroy); + +int +_pthread_mutexattr_destroy(pthread_mutexattr_t *attr) +{ + int ret; + if (attr == NULL || *attr == NULL) { + ret = EINVAL; + } else { + free(*attr); + *attr = NULL; + ret = 0; + } + return(ret); +} diff --git a/lib/libc_r/uthread/uthread_nanosleep.c b/lib/libc_r/uthread/uthread_nanosleep.c new file mode 100644 index 0000000..e5569e7 --- /dev/null +++ b/lib/libc_r/uthread/uthread_nanosleep.c @@ -0,0 +1,143 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <stdio.h> +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(__nanosleep, nanosleep); + +int +_nanosleep(const struct timespec * time_to_sleep, + struct timespec * time_remaining) +{ + struct pthread *curthread = _get_curthread(); + int ret = 0; + struct timespec current_time; + struct timespec current_time1; + struct timespec remaining_time; + struct timeval tv; + + /* Check if the time to sleep is legal: */ + if (time_to_sleep == NULL || time_to_sleep->tv_sec < 0 || + time_to_sleep->tv_nsec < 0 || time_to_sleep->tv_nsec >= 1000000000) { + /* Return an EINVAL error : */ + errno = EINVAL; + ret = -1; + } else { + /* + * As long as we're going to get the time of day, we + * might as well store it in the global time of day: + */ + gettimeofday((struct timeval *) &_sched_tod, NULL); + GET_CURRENT_TOD(tv); + TIMEVAL_TO_TIMESPEC(&tv, ¤t_time); + + /* Calculate the time for the current thread to wake up: */ + curthread->wakeup_time.tv_sec = current_time.tv_sec + time_to_sleep->tv_sec; + curthread->wakeup_time.tv_nsec = current_time.tv_nsec + time_to_sleep->tv_nsec; + + /* Check if the nanosecond field has overflowed: */ + if (curthread->wakeup_time.tv_nsec >= 1000000000) { + /* Wrap the nanosecond field: */ + curthread->wakeup_time.tv_sec += 1; + curthread->wakeup_time.tv_nsec -= 1000000000; + } + curthread->interrupted = 0; + + /* Reschedule the current thread to sleep: */ + _thread_kern_sched_state(PS_SLEEP_WAIT, __FILE__, __LINE__); + + /* + * As long as we're going to get the time of day, we + * might as well store it in the global time of day: + */ + gettimeofday((struct timeval *) &_sched_tod, NULL); + GET_CURRENT_TOD(tv); + TIMEVAL_TO_TIMESPEC(&tv, ¤t_time1); + + /* Calculate the remaining time to sleep: */ + 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; + + /* Check if the nanosecond field has underflowed: */ + if (remaining_time.tv_nsec < 0) { + /* Handle the underflow: */ + remaining_time.tv_sec -= 1; + remaining_time.tv_nsec += 1000000000; + } + + /* Check if the nanosecond field has overflowed: */ + if (remaining_time.tv_nsec >= 1000000000) { + /* Handle the overflow: */ + remaining_time.tv_sec += 1; + remaining_time.tv_nsec -= 1000000000; + } + + /* Check if the sleep was longer than the required time: */ + if (remaining_time.tv_sec < 0) { + /* Reset the time left: */ + remaining_time.tv_sec = 0; + remaining_time.tv_nsec = 0; + } + + /* Check if the time remaining is to be returned: */ + if (time_remaining != NULL) { + /* Return the actual time slept: */ + time_remaining->tv_sec = remaining_time.tv_sec; + time_remaining->tv_nsec = remaining_time.tv_nsec; + } + + /* Check if the sleep was interrupted: */ + if (curthread->interrupted) { + /* Return an EINTR error : */ + errno = EINTR; + ret = -1; + } + } + return (ret); +} + +int +__nanosleep(const struct timespec * time_to_sleep, struct timespec * + time_remaining) +{ + int ret; + + _thread_enter_cancellation_point(); + ret = _nanosleep(time_to_sleep, time_remaining); + _thread_leave_cancellation_point(); + + return ret; +} diff --git a/lib/libc_r/uthread/uthread_once.c b/lib/libc_r/uthread/uthread_once.c new file mode 100644 index 0000000..20e2904 --- /dev/null +++ b/lib/libc_r/uthread/uthread_once.c @@ -0,0 +1,53 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_once, pthread_once); + +int +_pthread_once(pthread_once_t * once_control, void (*init_routine) (void)) +{ + if (once_control->state == PTHREAD_NEEDS_INIT) { + if (_thread_initial == NULL) + _thread_init(); + pthread_mutex_lock(&(once_control->mutex)); + if (once_control->state == PTHREAD_NEEDS_INIT) { + init_routine(); + once_control->state = PTHREAD_DONE_INIT; + } + pthread_mutex_unlock(&(once_control->mutex)); + } + return (0); +} diff --git a/lib/libc_r/uthread/uthread_open.c b/lib/libc_r/uthread/uthread_open.c new file mode 100644 index 0000000..380761b --- /dev/null +++ b/lib/libc_r/uthread/uthread_open.c @@ -0,0 +1,96 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + * + */ +#include <stdarg.h> +#include <unistd.h> +#include <fcntl.h> +#include <dirent.h> +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(__open, open); + +int +_open(const char *path, int flags,...) +{ + int fd; + int mode = 0; + va_list ap; + + /* Check if the file is being created: */ + if (flags & O_CREAT) { + /* Get the creation mode: */ + va_start(ap, flags); + mode = va_arg(ap, int); + va_end(ap); + } + /* Open the file: */ + if ((fd = __sys_open(path, flags, mode)) < 0) { + } + /* Initialise the file descriptor table entry: */ + else if (_thread_fd_table_init(fd) != 0) { + /* Quietly close the file: */ + __sys_close(fd); + + /* Reset the file descriptor: */ + fd = -1; + } + + /* Return the file descriptor or -1 on error: */ + return (fd); +} + +int +__open(const char *path, int flags,...) +{ + int ret; + int mode = 0; + va_list ap; + + _thread_enter_cancellation_point(); + + /* Check if the file is being created: */ + if (flags & O_CREAT) { + /* Get the creation mode: */ + va_start(ap, flags); + mode = va_arg(ap, int); + va_end(ap); + } + + ret = _open(path, flags, mode); + _thread_leave_cancellation_point(); + + return ret; +} diff --git a/lib/libc_r/uthread/uthread_pause.c b/lib/libc_r/uthread/uthread_pause.c new file mode 100644 index 0000000..57b508f --- /dev/null +++ b/lib/libc_r/uthread/uthread_pause.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. + * 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(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) 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. + * + * $FreeBSD$ + */ + +#include <unistd.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pause, pause); + +int +_pause(void) +{ + int ret; + + _thread_enter_cancellation_point(); + ret = __pause(); + _thread_leave_cancellation_point(); + + return ret; +} diff --git a/lib/libc_r/uthread/uthread_pipe.c b/lib/libc_r/uthread/uthread_pipe.c new file mode 100644 index 0000000..f47e7d6 --- /dev/null +++ b/lib/libc_r/uthread/uthread_pipe.c @@ -0,0 +1,54 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <unistd.h> +#include <fcntl.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pipe, pipe); + +int +_pipe(int fds[2]) +{ + int ret; + if ((ret = __sys_pipe(fds)) >= 0) { + if (_thread_fd_table_init(fds[0]) != 0 || + _thread_fd_table_init(fds[1]) != 0) { + __sys_close(fds[0]); + __sys_close(fds[1]); + ret = -1; + } + } + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_poll.c b/lib/libc_r/uthread/uthread_poll.c new file mode 100644 index 0000000..e2a7cc0 --- /dev/null +++ b/lib/libc_r/uthread/uthread_poll.c @@ -0,0 +1,99 @@ +/* + * Copyright (c) 1999 Daniel Eischen <eischen@vigrid.com> + * 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 Daniel Eischen. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <unistd.h> +#include <errno.h> +#include <string.h> +#include <poll.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/fcntl.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_poll, poll); + +int +_poll(struct pollfd *fds, unsigned int nfds, int timeout) +{ + struct pthread *curthread = _get_curthread(); + struct timespec ts; + int numfds = nfds; + int i, ret = 0; + struct pthread_poll_data data; + + if (numfds > _thread_dtablesize) { + numfds = _thread_dtablesize; + } + /* Check if a timeout was specified: */ + if (timeout == INFTIM) { + /* Wait for ever: */ + _thread_kern_set_timeout(NULL); + } else if (timeout > 0) { + /* Convert the timeout in msec to a timespec: */ + ts.tv_sec = timeout / 1000; + ts.tv_nsec = (timeout % 1000) * 1000000; + + /* Set the wake up time: */ + _thread_kern_set_timeout(&ts); + } else if (timeout < 0) { + /* a timeout less than zero but not == INFTIM is invalid */ + errno = EINVAL; + return (-1); + } + + if (((ret = __sys_poll(fds, numfds, 0)) == 0) && (timeout != 0)) { + data.nfds = numfds; + data.fds = fds; + + /* + * Clear revents in case of a timeout which leaves fds + * unchanged: + */ + for (i = 0; i < numfds; i++) { + fds[i].revents = 0; + } + + curthread->data.poll_data = &data; + curthread->interrupted = 0; + _thread_kern_sched_state(PS_POLL_WAIT, __FILE__, __LINE__); + if (curthread->interrupted) { + errno = EINTR; + ret = -1; + } else { + ret = data.nfds; + } + } + + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_priority_queue.c b/lib/libc_r/uthread/uthread_priority_queue.c new file mode 100644 index 0000000..55d742b --- /dev/null +++ b/lib/libc_r/uthread/uthread_priority_queue.c @@ -0,0 +1,337 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * 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 Daniel Eischen. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <stdlib.h> +#include <sys/queue.h> +#include <string.h> +#include <pthread.h> +#include "pthread_private.h" + +/* Prototypes: */ +static void pq_insert_prio_list(pq_queue_t *pq, int prio); + +#if defined(_PTHREADS_INVARIANTS) + +static int _pq_active = 0; + +#define _PQ_IN_SCHEDQ (PTHREAD_FLAGS_IN_PRIOQ | PTHREAD_FLAGS_IN_WAITQ | PTHREAD_FLAGS_IN_WORKQ) + +#define _PQ_SET_ACTIVE() _pq_active = 1 +#define _PQ_CLEAR_ACTIVE() _pq_active = 0 +#define _PQ_ASSERT_ACTIVE(msg) do { \ + if (_pq_active == 0) \ + PANIC(msg); \ +} while (0) +#define _PQ_ASSERT_INACTIVE(msg) do { \ + if (_pq_active != 0) \ + PANIC(msg); \ +} while (0) +#define _PQ_ASSERT_IN_WAITQ(thrd, msg) do { \ + if (((thrd)->flags & PTHREAD_FLAGS_IN_WAITQ) == 0) \ + PANIC(msg); \ +} while (0) +#define _PQ_ASSERT_IN_PRIOQ(thrd, msg) do { \ + if (((thrd)->flags & PTHREAD_FLAGS_IN_PRIOQ) == 0) \ + PANIC(msg); \ +} while (0) +#define _PQ_ASSERT_NOT_QUEUED(thrd, msg) do { \ + if (((thrd)->flags & _PQ_IN_SCHEDQ) != 0) \ + PANIC(msg); \ +} while (0) +#define _PQ_ASSERT_PROTECTED(msg) \ + PTHREAD_ASSERT((_thread_kern_in_sched != 0) || \ + ((_get_curthread())->sig_defer_count > 0) ||\ + (_sig_in_handler != 0), msg); + +#else + +#define _PQ_SET_ACTIVE() +#define _PQ_CLEAR_ACTIVE() +#define _PQ_ASSERT_ACTIVE(msg) +#define _PQ_ASSERT_INACTIVE(msg) +#define _PQ_ASSERT_IN_WAITQ(thrd, msg) +#define _PQ_ASSERT_IN_PRIOQ(thrd, msg) +#define _PQ_ASSERT_NOT_QUEUED(thrd, msg) +#define _PQ_ASSERT_PROTECTED(msg) + +#endif + +int +_pq_alloc(pq_queue_t *pq, int minprio, int maxprio) +{ + int ret = 0; + int prioslots = maxprio - minprio + 1; + + if (pq == NULL) + ret = -1; + + /* Create the priority queue with (maxprio - minprio + 1) slots: */ + else if ((pq->pq_lists = + (pq_list_t *) malloc(sizeof(pq_list_t) * prioslots)) == NULL) + ret = -1; + + else { + /* Remember the queue size: */ + pq->pq_size = prioslots; + ret = _pq_init(pq); + } + return (ret); +} + +int +_pq_init(pq_queue_t *pq) +{ + int i, ret = 0; + + if ((pq == NULL) || (pq->pq_lists == NULL)) + ret = -1; + + else { + /* Initialize the queue for each priority slot: */ + for (i = 0; i < pq->pq_size; i++) { + TAILQ_INIT(&pq->pq_lists[i].pl_head); + pq->pq_lists[i].pl_prio = i; + pq->pq_lists[i].pl_queued = 0; + } + + /* Initialize the priority queue: */ + TAILQ_INIT(&pq->pq_queue); + _PQ_CLEAR_ACTIVE(); + } + return (ret); +} + +void +_pq_remove(pq_queue_t *pq, pthread_t pthread) +{ + int prio = pthread->active_priority; + + /* + * Make some assertions when debugging is enabled: + */ + _PQ_ASSERT_INACTIVE("_pq_remove: pq_active"); + _PQ_SET_ACTIVE(); + _PQ_ASSERT_IN_PRIOQ(pthread, "_pq_remove: Not in priority queue"); + _PQ_ASSERT_PROTECTED("_pq_remove: prioq not protected!"); + + /* + * Remove this thread from priority list. Note that if + * the priority list becomes empty, it is not removed + * from the priority queue because another thread may be + * added to the priority list (resulting in a needless + * removal/insertion). Priority lists are only removed + * from the priority queue when _pq_first is called. + */ + TAILQ_REMOVE(&pq->pq_lists[prio].pl_head, pthread, pqe); + + /* This thread is now longer in the priority queue. */ + pthread->flags &= ~PTHREAD_FLAGS_IN_PRIOQ; + + _PQ_CLEAR_ACTIVE(); +} + + +void +_pq_insert_head(pq_queue_t *pq, pthread_t pthread) +{ + int prio = pthread->active_priority; + + /* + * Make some assertions when debugging is enabled: + */ + _PQ_ASSERT_INACTIVE("_pq_insert_head: pq_active"); + _PQ_SET_ACTIVE(); + _PQ_ASSERT_NOT_QUEUED(pthread, + "_pq_insert_head: Already in priority queue"); + _PQ_ASSERT_PROTECTED("_pq_insert_head: prioq not protected!"); + + TAILQ_INSERT_HEAD(&pq->pq_lists[prio].pl_head, pthread, pqe); + if (pq->pq_lists[prio].pl_queued == 0) + /* Insert the list into the priority queue: */ + pq_insert_prio_list(pq, prio); + + /* Mark this thread as being in the priority queue. */ + pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ; + + _PQ_CLEAR_ACTIVE(); +} + + +void +_pq_insert_tail(pq_queue_t *pq, pthread_t pthread) +{ + int prio = pthread->active_priority; + + /* + * Make some assertions when debugging is enabled: + */ + _PQ_ASSERT_INACTIVE("_pq_insert_tail: pq_active"); + _PQ_SET_ACTIVE(); + _PQ_ASSERT_NOT_QUEUED(pthread, + "_pq_insert_tail: Already in priority queue"); + _PQ_ASSERT_PROTECTED("_pq_insert_tail: prioq not protected!"); + + TAILQ_INSERT_TAIL(&pq->pq_lists[prio].pl_head, pthread, pqe); + if (pq->pq_lists[prio].pl_queued == 0) + /* Insert the list into the priority queue: */ + pq_insert_prio_list(pq, prio); + + /* Mark this thread as being in the priority queue. */ + pthread->flags |= PTHREAD_FLAGS_IN_PRIOQ; + + _PQ_CLEAR_ACTIVE(); +} + + +pthread_t +_pq_first(pq_queue_t *pq) +{ + pq_list_t *pql; + pthread_t pthread = NULL; + + /* + * Make some assertions when debugging is enabled: + */ + _PQ_ASSERT_INACTIVE("_pq_first: pq_active"); + _PQ_SET_ACTIVE(); + _PQ_ASSERT_PROTECTED("_pq_first: prioq not protected!"); + + while (((pql = TAILQ_FIRST(&pq->pq_queue)) != NULL) && + (pthread == NULL)) { + if ((pthread = TAILQ_FIRST(&pql->pl_head)) == NULL) { + /* + * The priority list is empty; remove the list + * from the queue. + */ + TAILQ_REMOVE(&pq->pq_queue, pql, pl_link); + + /* Mark the list as not being in the queue: */ + pql->pl_queued = 0; + } + } + + _PQ_CLEAR_ACTIVE(); + return (pthread); +} + + +static void +pq_insert_prio_list(pq_queue_t *pq, int prio) +{ + pq_list_t *pql; + + /* + * Make some assertions when debugging is enabled: + */ + _PQ_ASSERT_ACTIVE("pq_insert_prio_list: pq_active"); + _PQ_ASSERT_PROTECTED("_pq_insert_prio_list: prioq not protected!"); + + /* + * The priority queue is in descending priority order. Start at + * the beginning of the queue and find the list before which the + * new list should be inserted. + */ + pql = TAILQ_FIRST(&pq->pq_queue); + while ((pql != NULL) && (pql->pl_prio > prio)) + pql = TAILQ_NEXT(pql, pl_link); + + /* Insert the list: */ + if (pql == NULL) + TAILQ_INSERT_TAIL(&pq->pq_queue, &pq->pq_lists[prio], pl_link); + else + TAILQ_INSERT_BEFORE(pql, &pq->pq_lists[prio], pl_link); + + /* Mark this list as being in the queue: */ + pq->pq_lists[prio].pl_queued = 1; +} + +void +_waitq_insert(pthread_t pthread) +{ + pthread_t tid; + + /* + * Make some assertions when debugging is enabled: + */ + _PQ_ASSERT_INACTIVE("_waitq_insert: pq_active"); + _PQ_SET_ACTIVE(); + _PQ_ASSERT_NOT_QUEUED(pthread, "_waitq_insert: Already in queue"); + + if (pthread->wakeup_time.tv_sec == -1) + TAILQ_INSERT_TAIL(&_waitingq, pthread, pqe); + else { + tid = TAILQ_FIRST(&_waitingq); + while ((tid != NULL) && (tid->wakeup_time.tv_sec != -1) && + ((tid->wakeup_time.tv_sec < pthread->wakeup_time.tv_sec) || + ((tid->wakeup_time.tv_sec == pthread->wakeup_time.tv_sec) && + (tid->wakeup_time.tv_nsec <= pthread->wakeup_time.tv_nsec)))) + tid = TAILQ_NEXT(tid, pqe); + if (tid == NULL) + TAILQ_INSERT_TAIL(&_waitingq, pthread, pqe); + else + TAILQ_INSERT_BEFORE(tid, pthread, pqe); + } + pthread->flags |= PTHREAD_FLAGS_IN_WAITQ; + + _PQ_CLEAR_ACTIVE(); +} + +void +_waitq_remove(pthread_t pthread) +{ + /* + * Make some assertions when debugging is enabled: + */ + _PQ_ASSERT_INACTIVE("_waitq_remove: pq_active"); + _PQ_SET_ACTIVE(); + _PQ_ASSERT_IN_WAITQ(pthread, "_waitq_remove: Not in queue"); + + TAILQ_REMOVE(&_waitingq, pthread, pqe); + pthread->flags &= ~PTHREAD_FLAGS_IN_WAITQ; + + _PQ_CLEAR_ACTIVE(); +} + +void +_waitq_setactive(void) +{ + _PQ_ASSERT_INACTIVE("_waitq_setactive: pq_active"); + _PQ_SET_ACTIVE(); +} + +void +_waitq_clearactive(void) +{ + _PQ_ASSERT_ACTIVE("_waitq_clearactive: ! pq_active"); + _PQ_CLEAR_ACTIVE(); +} diff --git a/lib/libc_r/uthread/uthread_read.c b/lib/libc_r/uthread/uthread_read.c new file mode 100644 index 0000000..4d81414 --- /dev/null +++ b/lib/libc_r/uthread/uthread_read.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + * + */ +#include <sys/types.h> +#include <sys/fcntl.h> +#include <sys/uio.h> +#include <errno.h> +#include <unistd.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(__read, read); + +ssize_t +_read(int fd, void *buf, size_t nbytes) +{ + struct pthread *curthread = _get_curthread(); + int ret; + int type; + + /* POSIX says to do just this: */ + if (nbytes == 0) { + return (0); + } + + /* Lock the file descriptor for read: */ + if ((ret = _FD_LOCK(fd, FD_READ, NULL)) == 0) { + /* Get the read/write mode type: */ + type = _thread_fd_table[fd]->flags & O_ACCMODE; + + /* Check if the file is not open for read: */ + if (type != O_RDONLY && type != O_RDWR) { + /* File is not open for read: */ + errno = EBADF; + _FD_UNLOCK(fd, FD_READ); + return (-1); + } + + /* Perform a non-blocking read syscall: */ + while ((ret = __sys_read(fd, buf, nbytes)) < 0) { + if ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0 && + (errno == EWOULDBLOCK || errno == EAGAIN)) { + curthread->data.fd.fd = fd; + _thread_kern_set_timeout(NULL); + + /* Reset the interrupted operation flag: */ + curthread->interrupted = 0; + + _thread_kern_sched_state(PS_FDR_WAIT, + __FILE__, __LINE__); + + /* + * Check if the operation was + * interrupted by a signal + */ + if (curthread->interrupted) { + errno = EINTR; + ret = -1; + break; + } + } else { + break; + } + } + _FD_UNLOCK(fd, FD_READ); + } + return (ret); +} + +ssize_t +__read(int fd, void *buf, size_t nbytes) +{ + ssize_t ret; + + _thread_enter_cancellation_point(); + ret = _read(fd, buf, nbytes); + _thread_leave_cancellation_point(); + + return ret; +} diff --git a/lib/libc_r/uthread/uthread_readv.c b/lib/libc_r/uthread/uthread_readv.c new file mode 100644 index 0000000..2759819 --- /dev/null +++ b/lib/libc_r/uthread/uthread_readv.c @@ -0,0 +1,94 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + * + */ +#include <sys/types.h> +#include <sys/fcntl.h> +#include <sys/uio.h> +#include <errno.h> +#include <unistd.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_readv, readv); + +ssize_t +_readv(int fd, const struct iovec * iov, int iovcnt) +{ + struct pthread *curthread = _get_curthread(); + int ret; + int type; + + /* Lock the file descriptor for read: */ + if ((ret = _FD_LOCK(fd, FD_READ, NULL)) == 0) { + /* Get the read/write mode type: */ + type = _thread_fd_table[fd]->flags & O_ACCMODE; + + /* Check if the file is not open for read: */ + if (type != O_RDONLY && type != O_RDWR) { + /* File is not open for read: */ + errno = EBADF; + _FD_UNLOCK(fd, FD_READ); + return (-1); + } + + /* Perform a non-blocking readv syscall: */ + while ((ret = __sys_readv(fd, iov, iovcnt)) < 0) { + if ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0 && + (errno == EWOULDBLOCK || errno == EAGAIN)) { + curthread->data.fd.fd = fd; + _thread_kern_set_timeout(NULL); + + /* Reset the interrupted operation flag: */ + curthread->interrupted = 0; + + _thread_kern_sched_state(PS_FDR_WAIT, + __FILE__, __LINE__); + + /* + * Check if the operation was + * interrupted by a signal + */ + if (curthread->interrupted) { + errno = EINTR; + ret = -1; + break; + } + } else { + break; + } + } + _FD_UNLOCK(fd, FD_READ); + } + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_recvfrom.c b/lib/libc_r/uthread/uthread_recvfrom.c new file mode 100644 index 0000000..0643126 --- /dev/null +++ b/lib/libc_r/uthread/uthread_recvfrom.c @@ -0,0 +1,75 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <fcntl.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_recvfrom, recvfrom); + +ssize_t +_recvfrom(int fd, void *buf, size_t len, int flags, struct sockaddr * from, + socklen_t *from_len) +{ + struct pthread *curthread = _get_curthread(); + int ret; + + if ((ret = _FD_LOCK(fd, FD_READ, NULL)) == 0) { + while ((ret = __sys_recvfrom(fd, buf, len, flags, from, from_len)) < 0) { + if (!(_thread_fd_table[fd]->flags & O_NONBLOCK) && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) { + curthread->data.fd.fd = fd; + + /* Set the timeout: */ + _thread_kern_set_timeout(NULL); + curthread->interrupted = 0; + _thread_kern_sched_state(PS_FDR_WAIT, __FILE__, __LINE__); + + /* Check if the wait was interrupted: */ + if (curthread->interrupted) { + /* Return an error status: */ + errno = EINTR; + ret = -1; + break; + } + } else { + ret = -1; + break; + } + } + _FD_UNLOCK(fd, FD_READ); + } + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_recvmsg.c b/lib/libc_r/uthread/uthread_recvmsg.c new file mode 100644 index 0000000..f3932aa --- /dev/null +++ b/lib/libc_r/uthread/uthread_recvmsg.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <fcntl.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_recvmsg, recvmsg); + +ssize_t +_recvmsg(int fd, struct msghdr *msg, int flags) +{ + struct pthread *curthread = _get_curthread(); + int ret; + + if ((ret = _FD_LOCK(fd, FD_READ, NULL)) == 0) { + while ((ret = __sys_recvmsg(fd, msg, flags)) < 0) { + if (!(_thread_fd_table[fd]->flags & O_NONBLOCK) && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) { + curthread->data.fd.fd = fd; + + /* Set the timeout: */ + _thread_kern_set_timeout(NULL); + curthread->interrupted = 0; + _thread_kern_sched_state(PS_FDR_WAIT, __FILE__, __LINE__); + + /* Check if the wait was interrupted: */ + if (curthread->interrupted) { + /* Return an error status: */ + errno = EINTR; + ret = -1; + break; + } + } else { + ret = -1; + break; + } + } + _FD_UNLOCK(fd, FD_READ); + } + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_resume_np.c b/lib/libc_r/uthread/uthread_resume_np.c new file mode 100644 index 0000000..9cbcf85 --- /dev/null +++ b/lib/libc_r/uthread/uthread_resume_np.c @@ -0,0 +1,96 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_resume_np, pthread_resume_np); + +/* Resume a thread: */ +int +_pthread_resume_np(pthread_t thread) +{ + int ret; + enum pthread_susp old_suspended; + + /* Find the thread in the list of active threads: */ + if ((ret = _find_thread(thread)) == 0) { + /* Cancel any pending suspensions: */ + old_suspended = thread->suspended; + thread->suspended = SUSP_NO; + + /* Is it currently suspended? */ + if (thread->state == PS_SUSPENDED) { + /* + * Defer signals to protect the scheduling queues + * from access by the signal handler: + */ + _thread_kern_sig_defer(); + + switch (old_suspended) { + case SUSP_MUTEX_WAIT: + /* Set the thread's state back. */ + PTHREAD_SET_STATE(thread,PS_MUTEX_WAIT); + break; + case SUSP_COND_WAIT: + /* Set the thread's state back. */ + PTHREAD_SET_STATE(thread,PS_COND_WAIT); + break; + case SUSP_JOIN: + /* Set the thread's state back. */ + PTHREAD_SET_STATE(thread,PS_JOIN); + break; + case SUSP_NOWAIT: + /* Allow the thread to run. */ + PTHREAD_SET_STATE(thread,PS_RUNNING); + PTHREAD_WAITQ_REMOVE(thread); + PTHREAD_PRIOQ_INSERT_TAIL(thread); + break; + case SUSP_NO: + case SUSP_YES: + /* Allow the thread to run. */ + PTHREAD_SET_STATE(thread,PS_RUNNING); + PTHREAD_PRIOQ_INSERT_TAIL(thread); + break; + } + + /* + * Undefer and handle pending signals, yielding if + * necessary: + */ + _thread_kern_sig_undefer(); + } + } + return(ret); +} diff --git a/lib/libc_r/uthread/uthread_rwlock.c b/lib/libc_r/uthread/uthread_rwlock.c new file mode 100644 index 0000000..2f55f03 --- /dev/null +++ b/lib/libc_r/uthread/uthread_rwlock.c @@ -0,0 +1,341 @@ +/*- + * Copyright (c) 1998 Alex Nash + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include <errno.h> +#include <limits.h> +#include <stdlib.h> + +#include <pthread.h> +#include "pthread_private.h" + +/* maximum number of times a read lock may be obtained */ +#define MAX_READ_LOCKS (INT_MAX - 1) + +__weak_reference(_pthread_rwlock_destroy, pthread_rwlock_destroy); +__weak_reference(_pthread_rwlock_init, pthread_rwlock_init); +__weak_reference(_pthread_rwlock_rdlock, pthread_rwlock_rdlock); +__weak_reference(_pthread_rwlock_tryrdlock, pthread_rwlock_tryrdlock); +__weak_reference(_pthread_rwlock_trywrlock, pthread_rwlock_trywrlock); +__weak_reference(_pthread_rwlock_unlock, pthread_rwlock_unlock); +__weak_reference(_pthread_rwlock_wrlock, pthread_rwlock_wrlock); + +static int init_static (pthread_rwlock_t *rwlock); + +static spinlock_t static_init_lock = _SPINLOCK_INITIALIZER; + +static int +init_static (pthread_rwlock_t *rwlock) +{ + int ret; + + _SPINLOCK(&static_init_lock); + + if (*rwlock == NULL) + ret = pthread_rwlock_init(rwlock, NULL); + else + ret = 0; + + _SPINUNLOCK(&static_init_lock); + + return(ret); +} + +int +_pthread_rwlock_destroy (pthread_rwlock_t *rwlock) +{ + int ret; + + if (rwlock == NULL) + ret = EINVAL; + else { + pthread_rwlock_t prwlock; + + prwlock = *rwlock; + + pthread_mutex_destroy(&prwlock->lock); + pthread_cond_destroy(&prwlock->read_signal); + pthread_cond_destroy(&prwlock->write_signal); + free(prwlock); + + *rwlock = NULL; + + ret = 0; + } + + return(ret); +} + +int +_pthread_rwlock_init (pthread_rwlock_t *rwlock, const pthread_rwlockattr_t *attr) +{ + pthread_rwlock_t prwlock; + int ret; + + /* allocate rwlock object */ + prwlock = (pthread_rwlock_t)malloc(sizeof(struct pthread_rwlock)); + + if (prwlock == NULL) + return(ENOMEM); + + /* initialize the lock */ + if ((ret = pthread_mutex_init(&prwlock->lock, NULL)) != 0) + free(prwlock); + else { + /* initialize the read condition signal */ + ret = pthread_cond_init(&prwlock->read_signal, NULL); + + if (ret != 0) { + pthread_mutex_destroy(&prwlock->lock); + free(prwlock); + } else { + /* initialize the write condition signal */ + ret = pthread_cond_init(&prwlock->write_signal, NULL); + + if (ret != 0) { + pthread_cond_destroy(&prwlock->read_signal); + pthread_mutex_destroy(&prwlock->lock); + free(prwlock); + } else { + /* success */ + prwlock->state = 0; + prwlock->blocked_writers = 0; + + *rwlock = prwlock; + } + } + } + + return(ret); +} + +int +_pthread_rwlock_rdlock (pthread_rwlock_t *rwlock) +{ + pthread_rwlock_t prwlock; + int ret; + + if (rwlock == NULL) + return(EINVAL); + + prwlock = *rwlock; + + /* check for static initialization */ + if (prwlock == NULL) { + if ((ret = init_static(rwlock)) != 0) + return(ret); + + prwlock = *rwlock; + } + + /* grab the monitor lock */ + if ((ret = pthread_mutex_lock(&prwlock->lock)) != 0) + return(ret); + + /* give writers priority over readers */ + while (prwlock->blocked_writers || prwlock->state < 0) { + ret = pthread_cond_wait(&prwlock->read_signal, &prwlock->lock); + + if (ret != 0) { + /* can't do a whole lot if this fails */ + pthread_mutex_unlock(&prwlock->lock); + return(ret); + } + } + + /* check lock count */ + if (prwlock->state == MAX_READ_LOCKS) + ret = EAGAIN; + else + ++prwlock->state; /* indicate we are locked for reading */ + + /* + * Something is really wrong if this call fails. Returning + * error won't do because we've already obtained the read + * lock. Decrementing 'state' is no good because we probably + * don't have the monitor lock. + */ + pthread_mutex_unlock(&prwlock->lock); + + return(ret); +} + +int +_pthread_rwlock_tryrdlock (pthread_rwlock_t *rwlock) +{ + pthread_rwlock_t prwlock; + int ret; + + if (rwlock == NULL) + return(EINVAL); + + prwlock = *rwlock; + + /* check for static initialization */ + if (prwlock == NULL) { + if ((ret = init_static(rwlock)) != 0) + return(ret); + + prwlock = *rwlock; + } + + /* grab the monitor lock */ + if ((ret = pthread_mutex_lock(&prwlock->lock)) != 0) + return(ret); + + /* give writers priority over readers */ + if (prwlock->blocked_writers || prwlock->state < 0) + ret = EBUSY; + else if (prwlock->state == MAX_READ_LOCKS) + ret = EAGAIN; /* too many read locks acquired */ + else + ++prwlock->state; /* indicate we are locked for reading */ + + /* see the comment on this in pthread_rwlock_rdlock */ + pthread_mutex_unlock(&prwlock->lock); + + return(ret); +} + +int +_pthread_rwlock_trywrlock (pthread_rwlock_t *rwlock) +{ + pthread_rwlock_t prwlock; + int ret; + + if (rwlock == NULL) + return(EINVAL); + + prwlock = *rwlock; + + /* check for static initialization */ + if (prwlock == NULL) { + if ((ret = init_static(rwlock)) != 0) + return(ret); + + prwlock = *rwlock; + } + + /* grab the monitor lock */ + if ((ret = pthread_mutex_lock(&prwlock->lock)) != 0) + return(ret); + + if (prwlock->state != 0) + ret = EBUSY; + else + /* indicate we are locked for writing */ + prwlock->state = -1; + + /* see the comment on this in pthread_rwlock_rdlock */ + pthread_mutex_unlock(&prwlock->lock); + + return(ret); +} + +int +_pthread_rwlock_unlock (pthread_rwlock_t *rwlock) +{ + pthread_rwlock_t prwlock; + int ret; + + if (rwlock == NULL) + return(EINVAL); + + prwlock = *rwlock; + + if (prwlock == NULL) + return(EINVAL); + + /* grab the monitor lock */ + if ((ret = pthread_mutex_lock(&prwlock->lock)) != 0) + return(ret); + + if (prwlock->state > 0) { + if (--prwlock->state == 0 && prwlock->blocked_writers) + ret = pthread_cond_signal(&prwlock->write_signal); + } else if (prwlock->state < 0) { + prwlock->state = 0; + + if (prwlock->blocked_writers) + ret = pthread_cond_signal(&prwlock->write_signal); + else + ret = pthread_cond_broadcast(&prwlock->read_signal); + } else + ret = EINVAL; + + /* see the comment on this in pthread_rwlock_rdlock */ + pthread_mutex_unlock(&prwlock->lock); + + return(ret); +} + +int +_pthread_rwlock_wrlock (pthread_rwlock_t *rwlock) +{ + pthread_rwlock_t prwlock; + int ret; + + if (rwlock == NULL) + return(EINVAL); + + prwlock = *rwlock; + + /* check for static initialization */ + if (prwlock == NULL) { + if ((ret = init_static(rwlock)) != 0) + return(ret); + + prwlock = *rwlock; + } + + /* grab the monitor lock */ + if ((ret = pthread_mutex_lock(&prwlock->lock)) != 0) + return(ret); + + while (prwlock->state != 0) { + ++prwlock->blocked_writers; + + ret = pthread_cond_wait(&prwlock->write_signal, &prwlock->lock); + + if (ret != 0) { + --prwlock->blocked_writers; + pthread_mutex_unlock(&prwlock->lock); + return(ret); + } + + --prwlock->blocked_writers; + } + + /* indicate we are locked for writing */ + prwlock->state = -1; + + /* see the comment on this in pthread_rwlock_rdlock */ + pthread_mutex_unlock(&prwlock->lock); + + return(ret); +} + diff --git a/lib/libc_r/uthread/uthread_rwlockattr.c b/lib/libc_r/uthread/uthread_rwlockattr.c new file mode 100644 index 0000000..bc1b9ee --- /dev/null +++ b/lib/libc_r/uthread/uthread_rwlockattr.c @@ -0,0 +1,98 @@ +/*- + * Copyright (c) 1998 Alex Nash + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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. + * + * $FreeBSD$ + */ + +#include <errno.h> +#include <stdlib.h> + +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_rwlockattr_destroy, pthread_rwlockattr_destroy); +__weak_reference(_pthread_rwlockattr_getpshared, pthread_rwlockattr_getpshared); +__weak_reference(_pthread_rwlockattr_init, pthread_rwlockattr_init); +__weak_reference(_pthread_rwlockattr_setpshared, pthread_rwlockattr_setpshared); + +int +_pthread_rwlockattr_destroy(pthread_rwlockattr_t *rwlockattr) +{ + pthread_rwlockattr_t prwlockattr; + + if (rwlockattr == NULL) + return(EINVAL); + + prwlockattr = *rwlockattr; + + if (prwlockattr == NULL) + return(EINVAL); + + free(prwlockattr); + + return(0); +} + +int +_pthread_rwlockattr_getpshared(const pthread_rwlockattr_t *rwlockattr, + int *pshared) +{ + *pshared = (*rwlockattr)->pshared; + + return(0); +} + +int +_pthread_rwlockattr_init(pthread_rwlockattr_t *rwlockattr) +{ + pthread_rwlockattr_t prwlockattr; + + if (rwlockattr == NULL) + return(EINVAL); + + prwlockattr = (pthread_rwlockattr_t) + malloc(sizeof(struct pthread_rwlockattr)); + + if (prwlockattr == NULL) + return(ENOMEM); + + prwlockattr->pshared = PTHREAD_PROCESS_PRIVATE; + *rwlockattr = prwlockattr; + + return(0); +} + +int +_pthread_rwlockattr_setpshared(pthread_rwlockattr_t *rwlockattr, int pshared) +{ + /* Only PTHREAD_PROCESS_PRIVATE is supported. */ + if (pshared != PTHREAD_PROCESS_PRIVATE) + return(EINVAL); + + (*rwlockattr)->pshared = pshared; + + return(0); +} + diff --git a/lib/libc_r/uthread/uthread_select.c b/lib/libc_r/uthread/uthread_select.c new file mode 100644 index 0000000..5860efe --- /dev/null +++ b/lib/libc_r/uthread/uthread_select.c @@ -0,0 +1,207 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <unistd.h> +#include <errno.h> +#include <poll.h> +#include <stdlib.h> +#include <string.h> +#include <sys/param.h> +#include <sys/types.h> +#include <sys/time.h> +#include <sys/fcntl.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_select, select); + +int +_select(int numfds, fd_set * readfds, fd_set * writefds, fd_set * exceptfds, + struct timeval * timeout) +{ + struct pthread *curthread = _get_curthread(); + struct timespec ts; + int i, ret = 0, f_wait = 1; + int pfd_index, got_one = 0, fd_count = 0; + struct pthread_poll_data data; + + if (numfds > _thread_dtablesize) { + numfds = _thread_dtablesize; + } + /* Check if a timeout was specified: */ + if (timeout) { + if (timeout->tv_sec < 0 || + timeout->tv_usec < 0 || timeout->tv_usec >= 1000000) { + errno = EINVAL; + return (-1); + } + + /* Convert the timeval to a timespec: */ + TIMEVAL_TO_TIMESPEC(timeout, &ts); + + /* Set the wake up time: */ + _thread_kern_set_timeout(&ts); + if (ts.tv_sec == 0 && ts.tv_nsec == 0) + f_wait = 0; + } else { + /* Wait for ever: */ + _thread_kern_set_timeout(NULL); + } + + /* Count the number of file descriptors to be polled: */ + if (readfds || writefds || exceptfds) { + for (i = 0; i < numfds; i++) { + if ((readfds && FD_ISSET(i, readfds)) || + (exceptfds && FD_ISSET(i, exceptfds)) || + (writefds && FD_ISSET(i, writefds))) { + fd_count++; + } + } + } + + /* + * Allocate memory for poll data if it hasn't already been + * allocated or if previously allocated memory is insufficient. + */ + if ((curthread->poll_data.fds == NULL) || + (curthread->poll_data.nfds < fd_count)) { + data.fds = (struct pollfd *) realloc(curthread->poll_data.fds, + sizeof(struct pollfd) * MAX(128, fd_count)); + if (data.fds == NULL) { + errno = ENOMEM; + ret = -1; + } + else { + /* + * Note that the threads poll data always + * indicates what is allocated, not what is + * currently being polled. + */ + curthread->poll_data.fds = data.fds; + curthread->poll_data.nfds = MAX(128, fd_count); + } + } + if (ret == 0) { + /* Setup the wait data. */ + data.fds = curthread->poll_data.fds; + data.nfds = fd_count; + + /* + * Setup the array of pollfds. Optimize this by + * running the loop in reverse and stopping when + * the number of selected file descriptors is reached. + */ + for (i = numfds - 1, pfd_index = fd_count - 1; + (i >= 0) && (pfd_index >= 0); i--) { + data.fds[pfd_index].events = 0; + if (readfds && FD_ISSET(i, readfds)) { + data.fds[pfd_index].events = POLLRDNORM; + } + if (exceptfds && FD_ISSET(i, exceptfds)) { + data.fds[pfd_index].events |= POLLRDBAND; + } + if (writefds && FD_ISSET(i, writefds)) { + data.fds[pfd_index].events |= POLLWRNORM; + } + if (data.fds[pfd_index].events != 0) { + /* + * Set the file descriptor to be polled and + * clear revents in case of a timeout which + * leaves fds unchanged: + */ + data.fds[pfd_index].fd = i; + data.fds[pfd_index].revents = 0; + pfd_index--; + } + } + if (((ret = __sys_poll(data.fds, data.nfds, 0)) == 0) && + (f_wait != 0)) { + curthread->data.poll_data = &data; + curthread->interrupted = 0; + _thread_kern_sched_state(PS_SELECT_WAIT, __FILE__, __LINE__); + if (curthread->interrupted) { + errno = EINTR; + data.nfds = 0; + ret = -1; + } else + ret = data.nfds; + } + } + + if (ret >= 0) { + numfds = 0; + for (i = 0; i < fd_count; i++) { + /* + * Check the results of the poll and clear + * this file descriptor from the fdset if + * the requested event wasn't ready. + */ + got_one = 0; + if (readfds != NULL) { + if (FD_ISSET(data.fds[i].fd, readfds)) { + if (data.fds[i].revents & (POLLIN | + POLLRDNORM)) + got_one = 1; + else + FD_CLR(data.fds[i].fd, readfds); + } + } + if (writefds != NULL) { + if (FD_ISSET(data.fds[i].fd, writefds)) { + if (data.fds[i].revents & (POLLOUT | + POLLWRNORM | POLLWRBAND)) + got_one = 1; + else + FD_CLR(data.fds[i].fd, + writefds); + } + } + if (exceptfds != NULL) { + if (FD_ISSET(data.fds[i].fd, exceptfds)) { + if (data.fds[i].revents & (POLLRDBAND | + POLLPRI | POLLHUP | POLLERR | + POLLNVAL)) + got_one = 1; + else + FD_CLR(data.fds[i].fd, + exceptfds); + } + } + if (got_one) + numfds++; + } + ret = numfds; + } + + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_self.c b/lib/libc_r/uthread/uthread_self.c new file mode 100644 index 0000000..1c09e3d --- /dev/null +++ b/lib/libc_r/uthread/uthread_self.c @@ -0,0 +1,44 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_self, pthread_self); + +pthread_t +_pthread_self(void) +{ + /* Return the running thread pointer: */ + return (_get_curthread()); +} diff --git a/lib/libc_r/uthread/uthread_sem.c b/lib/libc_r/uthread/uthread_sem.c new file mode 100644 index 0000000..851eca2 --- /dev/null +++ b/lib/libc_r/uthread/uthread_sem.c @@ -0,0 +1,254 @@ +/* + * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. + * 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(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) 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. + * + * $FreeBSD$ + */ + +#include <stdlib.h> +#include <errno.h> +#include <semaphore.h> +#include <pthread.h> +#include "pthread_private.h" + +#define _SEM_CHECK_VALIDITY(sem) \ + if ((*(sem))->magic != SEM_MAGIC) { \ + errno = EINVAL; \ + retval = -1; \ + goto RETURN; \ + } + +__weak_reference(_sem_init, sem_init); +__weak_reference(_sem_destroy, sem_destroy); +__weak_reference(_sem_open, sem_open); +__weak_reference(_sem_close, sem_close); +__weak_reference(_sem_unlink, sem_unlink); +__weak_reference(_sem_wait, sem_wait); +__weak_reference(_sem_trywait, sem_trywait); +__weak_reference(_sem_post, sem_post); +__weak_reference(_sem_getvalue, sem_getvalue); + + +int +_sem_init(sem_t *sem, int pshared, unsigned int value) +{ + int retval; + + /* + * Range check the arguments. + */ + if (pshared != 0) { + /* + * The user wants a semaphore that can be shared among + * processes, which this implementation can't do. Sounds like a + * permissions problem to me (yeah right). + */ + errno = EPERM; + retval = -1; + goto RETURN; + } + + if (value > SEM_VALUE_MAX) { + errno = EINVAL; + retval = -1; + goto RETURN; + } + + *sem = (sem_t)malloc(sizeof(struct sem)); + if (*sem == NULL) { + errno = ENOSPC; + retval = -1; + goto RETURN; + } + + /* + * Initialize the semaphore. + */ + if (pthread_mutex_init(&(*sem)->lock, NULL) != 0) { + free(*sem); + errno = ENOSPC; + retval = -1; + goto RETURN; + } + + if (pthread_cond_init(&(*sem)->gtzero, NULL) != 0) { + pthread_mutex_destroy(&(*sem)->lock); + free(*sem); + errno = ENOSPC; + retval = -1; + goto RETURN; + } + + (*sem)->count = (u_int32_t)value; + (*sem)->nwaiters = 0; + (*sem)->magic = SEM_MAGIC; + + retval = 0; + RETURN: + return retval; +} + +int +_sem_destroy(sem_t *sem) +{ + int retval; + + _SEM_CHECK_VALIDITY(sem); + + /* Make sure there are no waiters. */ + pthread_mutex_lock(&(*sem)->lock); + if ((*sem)->nwaiters > 0) { + pthread_mutex_unlock(&(*sem)->lock); + errno = EBUSY; + retval = -1; + goto RETURN; + } + pthread_mutex_unlock(&(*sem)->lock); + + pthread_mutex_destroy(&(*sem)->lock); + pthread_cond_destroy(&(*sem)->gtzero); + (*sem)->magic = 0; + + free(*sem); + + retval = 0; + RETURN: + return retval; +} + +sem_t * +_sem_open(const char *name, int oflag, ...) +{ + errno = ENOSYS; + return SEM_FAILED; +} + +int +_sem_close(sem_t *sem) +{ + errno = ENOSYS; + return -1; +} + +int +_sem_unlink(const char *name) +{ + errno = ENOSYS; + return -1; +} + +int +_sem_wait(sem_t *sem) +{ + int retval; + + _thread_enter_cancellation_point(); + + _SEM_CHECK_VALIDITY(sem); + + pthread_mutex_lock(&(*sem)->lock); + + while ((*sem)->count == 0) { + (*sem)->nwaiters++; + pthread_cond_wait(&(*sem)->gtzero, &(*sem)->lock); + (*sem)->nwaiters--; + } + (*sem)->count--; + + pthread_mutex_unlock(&(*sem)->lock); + + retval = 0; + RETURN: + _thread_leave_cancellation_point(); + return retval; +} + +int +_sem_trywait(sem_t *sem) +{ + int retval; + + _SEM_CHECK_VALIDITY(sem); + + pthread_mutex_lock(&(*sem)->lock); + + if ((*sem)->count > 0) { + (*sem)->count--; + retval = 0; + } else { + errno = EAGAIN; + retval = -1; + } + + pthread_mutex_unlock(&(*sem)->lock); + + RETURN: + return retval; +} + +int +_sem_post(sem_t *sem) +{ + int retval; + + _SEM_CHECK_VALIDITY(sem); + + /* + * sem_post() is required to be safe to call from within signal + * handlers. Thus, we must defer signals. + */ + _thread_kern_sig_defer(); + + pthread_mutex_lock(&(*sem)->lock); + + (*sem)->count++; + if ((*sem)->nwaiters > 0) + pthread_cond_signal(&(*sem)->gtzero); + + pthread_mutex_unlock(&(*sem)->lock); + + _thread_kern_sig_undefer(); + retval = 0; + RETURN: + return retval; +} + +int +_sem_getvalue(sem_t *sem, int *sval) +{ + int retval; + + _SEM_CHECK_VALIDITY(sem); + + pthread_mutex_lock(&(*sem)->lock); + *sval = (int)(*sem)->count; + pthread_mutex_unlock(&(*sem)->lock); + + retval = 0; + RETURN: + return retval; +} diff --git a/lib/libc_r/uthread/uthread_sendfile.c b/lib/libc_r/uthread/uthread_sendfile.c new file mode 100644 index 0000000..81dcf63 --- /dev/null +++ b/lib/libc_r/uthread/uthread_sendfile.c @@ -0,0 +1,194 @@ +/* + * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. + * 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(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) 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. + * + * $FreeBSD$ + */ + +#include <sys/fcntl.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/uio.h> +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_sendfile, sendfile); + +int +_sendfile(int fd, int s, off_t offset, size_t nbytes, struct sf_hdtr *hdtr, + off_t *sbytes, int flags) +{ + struct pthread *curthread = _get_curthread(); + int type, blocking; + int ret = 0; + ssize_t wvret, num = 0; + off_t n, nwritten = 0; + + /* + * Write the headers if any. + * If some data is written but not all we must return here. + */ + if ((hdtr != NULL) && (hdtr->headers != NULL)) { + if ((wvret = writev(s, hdtr->headers, hdtr->hdr_cnt)) == -1) { + ret = -1; + goto ERROR; + } else { + int i; + ssize_t hdrtot; + + nwritten += wvret; + + for (i = 0, hdrtot = 0; i < hdtr->hdr_cnt; i++) + hdrtot += hdtr->headers[i].iov_len; + if (wvret < hdrtot) + goto SHORT_WRITE; + } + } + + /* Lock the descriptors. */ + if ((ret = _FD_LOCK(fd, FD_READ, NULL)) != 0) { + ret = -1; + errno = EBADF; + goto ERROR; + } + if ((ret = _FD_LOCK(s, FD_WRITE, NULL)) != 0) { + ret = -1; + errno = EBADF; + goto ERROR_1; + } + + /* Check the descriptor access modes. */ + type = _thread_fd_table[fd]->flags & O_ACCMODE; + if (type != O_RDONLY && type != O_RDWR) { + /* File is not open for read. */ + ret = -1; + errno = EBADF; + goto ERROR_2; + } + type = _thread_fd_table[s]->flags & O_ACCMODE; + if (type != O_WRONLY && type != O_RDWR) { + /* File is not open for write. */ + ret = -1; + errno = EBADF; + goto ERROR_2; + } + + /* Check if file operations are to block */ + blocking = ((_thread_fd_table[s]->flags & O_NONBLOCK) == 0); + + /* + * Loop while no error occurs and until the expected number of bytes are + * written. + */ + for (;;) { + /* Perform a non-blocking sendfile syscall. */ + ret = __sys_sendfile(fd, s, offset + num, nbytes - num, + NULL, &n, flags); + + /* + * We have to handle the sideways return path of sendfile. + * + * If the result is 0, we're done. + * If the result is anything else check the errno. + * If the errno is not EGAIN return the error. + * Otherwise, take into account how much + * sendfile may have written for us because sendfile can + * return EAGAIN even though it has written data. + * + * We don't clear 'ret' because the sendfile(2) syscall + * would not have either. + */ + if (ret == 0) { + /* Writing completed. */ + num += n; + break; + } else if ((ret == -1) && (errno == EAGAIN)) { + /* + * Some bytes were written but there are still more to + * write. + */ + + /* Update the count of bytes written. */ + num += n; + + /* + * If we're not blocking then return. + */ + if (!blocking) { + _FD_UNLOCK(s, FD_WRITE); + _FD_UNLOCK(fd, FD_READ); + goto SHORT_WRITE; + } + + /* + * Otherwise wait on the fd. + */ + curthread->data.fd.fd = fd; + _thread_kern_set_timeout(NULL); + + /* Reset the interrupted operation flag. */ + curthread->interrupted = 0; + + _thread_kern_sched_state(PS_FDW_WAIT, __FILE__, + __LINE__); + + if (curthread->interrupted) { + /* Interrupted by a signal. Return an error. */ + break; + } + } else { + /* Incomplete non-blocking syscall, or error. */ + break; + } + } + + ERROR_2: + _FD_UNLOCK(s, FD_WRITE); + ERROR_1: + _FD_UNLOCK(fd, FD_READ); + ERROR: + if (ret == 0) { + /* Write the trailers, if any. */ + if ((hdtr != NULL) && (hdtr->trailers != NULL)) { + if ((wvret = writev(s, hdtr->trailers, hdtr->trl_cnt)) + == -1) + ret = -1; + else + nwritten += wvret; + } + } + SHORT_WRITE: + if (sbytes != NULL) { + /* + * Number of bytes written in headers/trailers, plus in the main + * sendfile() loop. + */ + *sbytes = nwritten + num; + } + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_sendmsg.c b/lib/libc_r/uthread/uthread_sendmsg.c new file mode 100644 index 0000000..5a3476b --- /dev/null +++ b/lib/libc_r/uthread/uthread_sendmsg.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <fcntl.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_sendmsg, sendmsg); + +ssize_t +_sendmsg(int fd, const struct msghdr *msg, int flags) +{ + struct pthread *curthread = _get_curthread(); + int ret; + + if ((ret = _FD_LOCK(fd, FD_WRITE, NULL)) == 0) { + while ((ret = __sys_sendmsg(fd, msg, flags)) < 0) { + if (!(_thread_fd_table[fd]->flags & O_NONBLOCK) && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) { + curthread->data.fd.fd = fd; + + /* Set the timeout: */ + _thread_kern_set_timeout(NULL); + curthread->interrupted = 0; + _thread_kern_sched_state(PS_FDW_WAIT, __FILE__, __LINE__); + + /* Check if the operation was interrupted: */ + if (curthread->interrupted) { + errno = EINTR; + ret = -1; + break; + } + } else { + ret = -1; + break; + } + } + _FD_UNLOCK(fd, FD_WRITE); + } + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_sendto.c b/lib/libc_r/uthread/uthread_sendto.c new file mode 100644 index 0000000..97f8718 --- /dev/null +++ b/lib/libc_r/uthread/uthread_sendto.c @@ -0,0 +1,74 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <fcntl.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_sendto, sendto); + +ssize_t +_sendto(int fd, const void *msg, size_t len, int flags, const struct + sockaddr * to, socklen_t to_len) +{ + struct pthread *curthread = _get_curthread(); + int ret; + + if ((ret = _FD_LOCK(fd, FD_WRITE, NULL)) == 0) { + while ((ret = __sys_sendto(fd, msg, len, flags, to, to_len)) < 0) { + if (!(_thread_fd_table[fd]->flags & O_NONBLOCK) && ((errno == EWOULDBLOCK) || (errno == EAGAIN))) { + curthread->data.fd.fd = fd; + + /* Set the timeout: */ + _thread_kern_set_timeout(NULL); + curthread->interrupted = 0; + _thread_kern_sched_state(PS_FDW_WAIT, __FILE__, __LINE__); + + /* Check if the operation was interrupted: */ + if (curthread->interrupted) { + errno = EINTR; + ret = -1; + break; + } + } else { + ret = -1; + break; + } + } + _FD_UNLOCK(fd, FD_WRITE); + } + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_seterrno.c b/lib/libc_r/uthread/uthread_seterrno.c new file mode 100644 index 0000000..0d9474f --- /dev/null +++ b/lib/libc_r/uthread/uthread_seterrno.c @@ -0,0 +1,59 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <pthread.h> +#include "pthread_private.h" + +/* + * This function needs to reference the global error variable which is + * normally hidden from the user. + */ +#ifdef errno +#undef errno; +#endif +extern int errno; + +void +_thread_seterrno(pthread_t thread, int error) +{ + /* Check for the initial thread: */ + if (thread == _thread_initial) + /* The initial thread always uses the global error variable: */ + errno = error; + else + /* + * Threads other than the initial thread always use the error + * field in the thread structureL + */ + thread->error = error; +} diff --git a/lib/libc_r/uthread/uthread_setprio.c b/lib/libc_r/uthread/uthread_setprio.c new file mode 100644 index 0000000..9099a6e --- /dev/null +++ b/lib/libc_r/uthread/uthread_setprio.c @@ -0,0 +1,52 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_setprio, pthread_setprio); + +int +_pthread_setprio(pthread_t pthread, int prio) +{ + int ret, policy; + struct sched_param param; + + if ((ret = pthread_getschedparam(pthread, &policy, ¶m)) == 0) { + param.sched_priority = prio; + ret = pthread_setschedparam(pthread, policy, ¶m); + } + + /* Return the error status: */ + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_setschedparam.c b/lib/libc_r/uthread/uthread_setschedparam.c new file mode 100644 index 0000000..7696762 --- /dev/null +++ b/lib/libc_r/uthread/uthread_setschedparam.c @@ -0,0 +1,119 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * 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 Daniel Eischen. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <sys/param.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_setschedparam, pthread_setschedparam); + +int +_pthread_setschedparam(pthread_t pthread, int policy, + const struct sched_param *param) +{ + int old_prio, in_readyq = 0, ret = 0; + + if ((param == NULL) || (policy < SCHED_FIFO) || (policy > SCHED_RR)) { + /* Return an invalid argument error: */ + ret = EINVAL; + } else if ((param->sched_priority < PTHREAD_MIN_PRIORITY) || + (param->sched_priority > PTHREAD_MAX_PRIORITY)) { + /* Return an unsupported value error. */ + ret = ENOTSUP; + + /* Find the thread in the list of active threads: */ + } else if ((ret = _find_thread(pthread)) == 0) { + /* + * Defer signals to protect the scheduling queues from + * access by the signal handler: + */ + _thread_kern_sig_defer(); + + if (param->sched_priority != + PTHREAD_BASE_PRIORITY(pthread->base_priority)) { + /* + * Remove the thread from its current priority + * queue before any adjustments are made to its + * active priority: + */ + old_prio = pthread->active_priority; + if ((pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) != 0) { + in_readyq = 1; + PTHREAD_PRIOQ_REMOVE(pthread); + } + + /* Set the thread base priority: */ + pthread->base_priority &= + (PTHREAD_SIGNAL_PRIORITY | PTHREAD_RT_PRIORITY); + pthread->base_priority = param->sched_priority; + + /* Recalculate the active priority: */ + pthread->active_priority = MAX(pthread->base_priority, + pthread->inherited_priority); + + if (in_readyq) { + if ((pthread->priority_mutex_count > 0) && + (old_prio > pthread->active_priority)) { + /* + * POSIX states that if the priority is + * being lowered, the thread must be + * inserted at the head of the queue for + * its priority if it owns any priority + * protection or inheritence mutexes. + */ + PTHREAD_PRIOQ_INSERT_HEAD(pthread); + } + else + PTHREAD_PRIOQ_INSERT_TAIL(pthread); + } + + /* + * Check for any mutex priority adjustments. This + * includes checking for a priority mutex on which + * this thread is waiting. + */ + _mutex_notify_priochange(pthread); + } + + /* Set the scheduling policy: */ + pthread->attr.sched_policy = policy; + + /* + * Undefer and handle pending signals, yielding if + * necessary: + */ + _thread_kern_sig_undefer(); + } + return(ret); +} diff --git a/lib/libc_r/uthread/uthread_setsockopt.c b/lib/libc_r/uthread/uthread_setsockopt.c new file mode 100644 index 0000000..081518c --- /dev/null +++ b/lib/libc_r/uthread/uthread_setsockopt.c @@ -0,0 +1,52 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <sys/types.h> +#include <sys/socket.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_setsockopt, setsockopt); + +int +_setsockopt(int fd, int level, int optname, const void *optval, socklen_t + optlen) +{ + int ret; + + if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) { + ret = __sys_setsockopt(fd, level, optname, optval, optlen); + _FD_UNLOCK(fd, FD_RDWR); + } + return ret; +} diff --git a/lib/libc_r/uthread/uthread_shutdown.c b/lib/libc_r/uthread/uthread_shutdown.c new file mode 100644 index 0000000..a148d85 --- /dev/null +++ b/lib/libc_r/uthread/uthread_shutdown.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_shutdown, shutdown); + +int +_shutdown(int fd, int how) +{ + int ret; + + switch (how) { + case 0: + if ((ret = _FD_LOCK(fd, FD_READ, NULL)) == 0) { + ret = __sys_shutdown(fd, how); + _FD_UNLOCK(fd, FD_READ); + } + break; + case 1: + if ((ret = _FD_LOCK(fd, FD_WRITE, NULL)) == 0) { + ret = __sys_shutdown(fd, how); + _FD_UNLOCK(fd, FD_WRITE); + } + break; + case 2: + if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) { + ret = __sys_shutdown(fd, how); + _FD_UNLOCK(fd, FD_RDWR); + } + break; + default: + errno = EBADF; + ret = -1; + break; + } + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_sig.c b/lib/libc_r/uthread/uthread_sig.c new file mode 100644 index 0000000..1bd93b7 --- /dev/null +++ b/lib/libc_r/uthread/uthread_sig.c @@ -0,0 +1,1117 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <sys/param.h> +#include <sys/types.h> +#include <sys/signalvar.h> +#include <signal.h> +#include <fcntl.h> +#include <unistd.h> +#include <setjmp.h> +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +/* Prototypes: */ +static void thread_sig_add(struct pthread *pthread, int sig, int has_args); +static void thread_sig_check_state(struct pthread *pthread, int sig); +static struct pthread *thread_sig_find(int sig); +static void thread_sig_handle_special(int sig); +static void thread_sigframe_add(struct pthread *thread, int sig, + int has_args); +static void thread_sigframe_save(struct pthread *thread, + struct pthread_signal_frame *psf); +static void thread_sig_invoke_handler(int sig, siginfo_t *info, + ucontext_t *ucp); + +/* #define DEBUG_SIGNAL */ +#ifdef DEBUG_SIGNAL +#define DBG_MSG stdout_debug +#else +#define DBG_MSG(x...) +#endif + +#if defined(_PTHREADS_INVARIANTS) +#define SIG_SET_ACTIVE() _sig_in_handler = 1 +#define SIG_SET_INACTIVE() _sig_in_handler = 0 +#else +#define SIG_SET_ACTIVE() +#define SIG_SET_INACTIVE() +#endif + +void +_thread_sig_handler(int sig, siginfo_t *info, ucontext_t *ucp) +{ + struct pthread *curthread = _get_curthread(); + struct pthread *pthread, *pthread_h; + int in_sched = _thread_kern_in_sched; + char c; + + if (ucp == NULL) + PANIC("Thread signal handler received null context"); + DBG_MSG("Got signal %d, current thread %p\n", sig, curthread); + + /* Check if an interval timer signal: */ + if (sig == _SCHED_SIGNAL) { + /* Update the scheduling clock: */ + gettimeofday((struct timeval *)&_sched_tod, NULL); + _sched_ticks++; + + if (in_sched != 0) { + /* + * The scheduler is already running; ignore this + * signal. + */ + } + /* + * Check if the scheduler interrupt has come when + * the currently running thread has deferred thread + * signals. + */ + else if (curthread->sig_defer_count > 0) + curthread->yield_on_sig_undefer = 1; + else { + /* Schedule the next thread: */ + _thread_kern_sched(ucp); + + /* + * This point should not be reached, so abort the + * process: + */ + PANIC("Returned to signal function from scheduler"); + } + } + /* + * Check if the kernel has been interrupted while the scheduler + * is accessing the scheduling queues or if there is a currently + * running thread that has deferred signals. + */ + else if ((in_sched != 0) || (curthread->sig_defer_count > 0)) { + /* Cast the signal number to a character variable: */ + c = sig; + + /* + * Write the signal number to the kernel pipe so that it will + * be ready to read when this signal handler returns. + */ + if (_queue_signals != 0) { + __sys_write(_thread_kern_pipe[1], &c, 1); + DBG_MSG("Got signal %d, queueing to kernel pipe\n", sig); + } + if (_thread_sigq[sig - 1].blocked == 0) { + DBG_MSG("Got signal %d, adding to _thread_sigq\n", sig); + /* + * Do not block this signal; it will be blocked + * when the pending signals are run down. + */ + /* _thread_sigq[sig - 1].blocked = 1; */ + + /* + * Queue the signal, saving siginfo and sigcontext + * (ucontext). + * + * XXX - Do we need to copy siginfo and ucp? + */ + _thread_sigq[sig - 1].signo = sig; + if (info != NULL) + memcpy(&_thread_sigq[sig - 1].siginfo, info, + sizeof(*info)); + memcpy(&_thread_sigq[sig - 1].uc, ucp, sizeof(*ucp)); + + /* Indicate that there are queued signals: */ + _thread_sigq[sig - 1].pending = 1; + _sigq_check_reqd = 1; + } + /* These signals need special handling: */ + else if (sig == SIGCHLD || sig == SIGTSTP || + sig == SIGTTIN || sig == SIGTTOU) { + _thread_sigq[sig - 1].pending = 1; + _thread_sigq[sig - 1].signo = sig; + _sigq_check_reqd = 1; + } + else + DBG_MSG("Got signal %d, ignored.\n", sig); + } + /* + * The signal handlers should have been installed so that they + * cannot be interrupted by other signals. + */ + else if (_thread_sigq[sig - 1].blocked == 0) { + /* + * The signal is not blocked; handle the signal. + * + * Ignore subsequent occurrences of this signal + * until the current signal is handled: + */ + _thread_sigq[sig - 1].blocked = 1; + + /* This signal will be handled; clear the pending flag: */ + _thread_sigq[sig - 1].pending = 0; + + /* + * Save siginfo and sigcontext (ucontext). + * + * XXX - Do we need to copy siginfo and ucp? + */ + _thread_sigq[sig - 1].signo = sig; + + if (info != NULL) + memcpy(&_thread_sigq[sig - 1].siginfo, info, + sizeof(*info)); + memcpy(&_thread_sigq[sig - 1].uc, ucp, sizeof(*ucp)); + SIG_SET_ACTIVE(); + + /* Handle special signals: */ + thread_sig_handle_special(sig); + + pthread_h = NULL; + if ((pthread = thread_sig_find(sig)) == NULL) + DBG_MSG("No thread to handle signal %d\n", sig); + else if (pthread == curthread) { + /* + * Unblock the signal and restore the process signal + * mask in case we don't return from the handler: + */ + _thread_sigq[sig - 1].blocked = 0; + __sys_sigprocmask(SIG_SETMASK, &_process_sigmask, NULL); + + /* Call the signal handler for the current thread: */ + thread_sig_invoke_handler(sig, info, ucp); + + /* + * Set the process signal mask in the context; it + * could have changed by the handler. + */ + ucp->uc_sigmask = _process_sigmask; + + /* Resume the interrupted thread: */ + __sys_sigreturn(ucp); + } else { + DBG_MSG("Got signal %d, adding frame to thread %p\n", + sig, pthread); + + /* Setup the target thread to receive the signal: */ + thread_sig_add(pthread, sig, /*has_args*/ 1); + + /* Take a peek at the next ready to run thread: */ + pthread_h = PTHREAD_PRIOQ_FIRST(); + DBG_MSG("Finished adding frame, head of prio list %p\n", + pthread_h); + } + SIG_SET_INACTIVE(); + + /* + * Switch to a different context if the currently running + * thread takes a signal, or if another thread takes a + * signal and the currently running thread is not in a + * signal handler. + */ + if ((pthread_h != NULL) && + (pthread_h->active_priority > curthread->active_priority)) { + /* Enter the kernel scheduler: */ + _thread_kern_sched(ucp); + } + } + else { + SIG_SET_ACTIVE(); + thread_sig_handle_special(sig); + SIG_SET_INACTIVE(); + } +} + +static void +thread_sig_invoke_handler(int sig, siginfo_t *info, ucontext_t *ucp) + { + struct pthread *curthread = _get_curthread(); + void (*sigfunc)(int, siginfo_t *, void *); + int saved_seqno; + sigset_t saved_sigmask; + + /* Invoke the signal handler without going through the scheduler: + */ + DBG_MSG("Got signal %d, calling handler for current thread %p\n", + sig, curthread); + + /* Save the threads signal mask: */ + saved_sigmask = curthread->sigmask; + saved_seqno = curthread->sigmask_seqno; + + /* Setup the threads signal mask: */ + SIGSETOR(curthread->sigmask, _thread_sigact[sig - 1].sa_mask); + sigaddset(&curthread->sigmask, sig); + + /* + * Check that a custom handler is installed and if + * the signal is not blocked: + */ + sigfunc = _thread_sigact[sig - 1].sa_sigaction; + if (((__sighandler_t *)sigfunc != SIG_DFL) && + ((__sighandler_t *)sigfunc != SIG_IGN)) { + if (((_thread_sigact[sig - 1].sa_flags & SA_SIGINFO) != 0) || + (info == NULL)) + (*(sigfunc))(sig, info, ucp); + else + (*(sigfunc))(sig, (siginfo_t *)info->si_code, ucp); + } + /* + * Only restore the signal mask if it hasn't been changed by the + * application during invocation of the signal handler: + */ + if (curthread->sigmask_seqno == saved_seqno) + curthread->sigmask = saved_sigmask; +} + +/* + * Find a thread that can handle the signal. + */ +struct pthread * +thread_sig_find(int sig) +{ + struct pthread *curthread = _get_curthread(); + int handler_installed; + struct pthread *pthread, *pthread_next; + struct pthread *suspended_thread, *signaled_thread; + + DBG_MSG("Looking for thread to handle signal %d\n", sig); + /* Check if the signal requires a dump of thread information: */ + if (sig == SIGINFO) { + /* Dump thread information to file: */ + _thread_dump_info(); + + /* Unblock this signal to allow further dumps: */ + _thread_sigq[sig - 1].blocked = 0; + } + /* Check if an interval timer signal: */ + else if (sig == _SCHED_SIGNAL) { + /* + * This shouldn't ever occur (should this panic?). + */ + } else { + /* + * Enter a loop to look for threads that have the signal + * unmasked. POSIX specifies that a thread in a sigwait + * will get the signal over any other threads. Second + * preference will be threads in in a sigsuspend. Third + * preference will be the current thread. If none of the + * above, then the signal is delivered to the first thread + * that is found. Note that if a custom handler is not + * installed, the signal only affects threads in sigwait. + */ + suspended_thread = NULL; + if ((curthread != &_thread_kern_thread) && + !sigismember(&curthread->sigmask, sig)) + signaled_thread = curthread; + else + signaled_thread = NULL; + if ((_thread_sigact[sig - 1].sa_handler == SIG_IGN) || + (_thread_sigact[sig - 1].sa_handler == SIG_DFL)) + handler_installed = 0; + else + handler_installed = 1; + + for (pthread = TAILQ_FIRST(&_waitingq); + pthread != NULL; pthread = pthread_next) { + /* + * Grab the next thread before possibly destroying + * the link entry. + */ + pthread_next = TAILQ_NEXT(pthread, pqe); + + if ((pthread->state == PS_SIGWAIT) && + sigismember(pthread->data.sigwait, sig)) { + /* Change the state of the thread to run: */ + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + /* + * A signal handler is not invoked for threads + * in sigwait. Clear the blocked and pending + * flags. + */ + _thread_sigq[sig - 1].blocked = 0; + _thread_sigq[sig - 1].pending = 0; + + /* Return the signal number: */ + pthread->signo = sig; + + /* + * POSIX doesn't doesn't specify which thread + * will get the signal if there are multiple + * waiters, so we give it to the first thread + * we find. + * + * Do not attempt to deliver this signal + * to other threads and do not add the signal + * to the process pending set. + */ + return (NULL); + } + else if ((handler_installed != 0) && + !sigismember(&pthread->sigmask, sig)) { + if (pthread->state == PS_SIGSUSPEND) { + if (suspended_thread == NULL) + suspended_thread = pthread; + } else if (signaled_thread == NULL) + signaled_thread = pthread; + } + } + + /* + * Only perform wakeups and signal delivery if there is a + * custom handler installed: + */ + if (handler_installed == 0) { + /* + * There is no handler installed. Unblock the + * signal so that if a handler _is_ installed, any + * subsequent signals can be handled. + */ + _thread_sigq[sig - 1].blocked = 0; + } else { + /* + * If we didn't find a thread in the waiting queue, + * check the all threads queue: + */ + if (suspended_thread == NULL && + signaled_thread == NULL) { + /* + * Enter a loop to look for other threads + * capable of receiving the signal: + */ + TAILQ_FOREACH(pthread, &_thread_list, tle) { + if (!sigismember(&pthread->sigmask, + sig)) { + signaled_thread = pthread; + break; + } + } + } + + if (suspended_thread == NULL && + signaled_thread == NULL) + /* + * Add it to the set of signals pending + * on the process: + */ + sigaddset(&_process_sigpending, sig); + else { + /* + * We only deliver the signal to one thread; + * give preference to the suspended thread: + */ + if (suspended_thread != NULL) + pthread = suspended_thread; + else + pthread = signaled_thread; + return (pthread); + } + } + } + + /* Returns nothing. */ + return (NULL); +} + +void +_thread_sig_check_pending(struct pthread *pthread) +{ + sigset_t sigset; + int i; + + /* + * Check if there are pending signals for the running + * thread or process that aren't blocked: + */ + sigset = pthread->sigpend; + SIGSETOR(sigset, _process_sigpending); + SIGSETNAND(sigset, pthread->sigmask); + if (SIGNOTEMPTY(sigset)) { + for (i = 1; i < NSIG; i++) { + if (sigismember(&sigset, i) != 0) { + if (sigismember(&pthread->sigpend, i) != 0) + thread_sig_add(pthread, i, + /*has_args*/ 0); + else { + thread_sig_add(pthread, i, + /*has_args*/ 1); + sigdelset(&_process_sigpending, i); + } + } + } + } +} + +/* + * This can only be called from the kernel scheduler. It assumes that + * all thread contexts are saved and that a signal frame can safely be + * added to any user thread. + */ +void +_thread_sig_handle_pending(void) +{ + struct pthread *pthread; + int i, sig; + + PTHREAD_ASSERT(_thread_kern_in_sched != 0, + "_thread_sig_handle_pending called from outside kernel schedule"); + /* + * Check the array of pending signals: + */ + for (i = 0; i < NSIG; i++) { + if (_thread_sigq[i].pending != 0) { + /* This signal is no longer pending. */ + _thread_sigq[i].pending = 0; + + sig = _thread_sigq[i].signo; + + /* Some signals need special handling: */ + thread_sig_handle_special(sig); + + if (_thread_sigq[i].blocked == 0) { + /* + * Block future signals until this one + * is handled: + */ + _thread_sigq[i].blocked = 1; + + if ((pthread = thread_sig_find(sig)) != NULL) { + /* + * Setup the target thread to receive + * the signal: + */ + thread_sig_add(pthread, sig, + /*has_args*/ 1); + } + } + } + } +} + +static void +thread_sig_handle_special(int sig) +{ + struct pthread *pthread, *pthread_next; + int i; + + switch (sig) { + case SIGCHLD: + /* + * 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: + */ + __sys_fcntl(i, F_SETFL, + _thread_fd_table[i]->flags | O_NONBLOCK); + } + } + /* + * Enter a loop to wake up all threads waiting + * for a process to complete: + */ + for (pthread = TAILQ_FIRST(&_waitingq); + pthread != NULL; pthread = pthread_next) { + /* + * Grab the next thread before possibly + * destroying the link entry: + */ + pthread_next = TAILQ_NEXT(pthread, pqe); + + /* + * If this thread is waiting for a child + * process to complete, wake it up: + */ + if (pthread->state == PS_WAIT_WAIT) { + /* Make the thread runnable: */ + PTHREAD_NEW_STATE(pthread,PS_RUNNING); + + /* Return the signal number: */ + pthread->signo = sig; + } + } + break; + + /* + * POSIX says that pending SIGCONT signals are + * discarded when one of these signals occurs. + */ + case SIGTSTP: + case SIGTTIN: + case SIGTTOU: + /* + * Enter a loop to discard pending SIGCONT + * signals: + */ + TAILQ_FOREACH(pthread, &_thread_list, tle) { + sigdelset(&pthread->sigpend, SIGCONT); + } + break; + + default: + break; + } +} + +/* + * Perform thread specific actions in response to a signal. + * This function is only called if there is a handler installed + * for the signal, and if the target thread has the signal + * unmasked. + */ +static void +thread_sig_add(struct pthread *pthread, int sig, int has_args) +{ + int restart; + int suppress_handler = 0; + int thread_is_active = 0; + + restart = _thread_sigact[sig - 1].sa_flags & SA_RESTART; + + /* Make sure this signal isn't still in the pending set: */ + sigdelset(&pthread->sigpend, sig); + + /* + * Process according to thread state: + */ + switch (pthread->state) { + /* + * States which do not change when a signal is trapped: + */ + case PS_DEAD: + case PS_DEADLOCK: + case PS_STATE_MAX: + case PS_SIGTHREAD: + /* + * You can't call a signal handler for threads in these + * states. + */ + suppress_handler = 1; + break; + + /* + * States which do not need any cleanup handling when signals + * occur: + */ + case PS_RUNNING: + /* + * Remove the thread from the queue before changing its + * priority: + */ + if ((pthread->flags & PTHREAD_FLAGS_IN_PRIOQ) != 0) + PTHREAD_PRIOQ_REMOVE(pthread); + else + /* + * This thread is running; avoid placing it in + * the run queue: + */ + thread_is_active = 1; + break; + + case PS_SUSPENDED: + break; + + case PS_SPINBLOCK: + /* Remove the thread from the workq and waitq: */ + PTHREAD_WORKQ_REMOVE(pthread); + PTHREAD_WAITQ_REMOVE(pthread); + /* Make the thread runnable: */ + PTHREAD_SET_STATE(pthread, PS_RUNNING); + break; + + case PS_SIGWAIT: + /* The signal handler is not called for threads in SIGWAIT. */ + suppress_handler = 1; + /* Wake up the thread if the signal is blocked. */ + if (sigismember(pthread->data.sigwait, sig)) { + /* Change the state of the thread to run: */ + PTHREAD_NEW_STATE(pthread, PS_RUNNING); + + /* Return the signal number: */ + pthread->signo = sig; + } else + /* Increment the pending signal count. */ + sigaddset(&pthread->sigpend, sig); + break; + + /* + * The wait state is a special case due to the handling of + * SIGCHLD signals. + */ + case PS_WAIT_WAIT: + if (sig == SIGCHLD) { + /* Change the state of the thread to run: */ + PTHREAD_WAITQ_REMOVE(pthread); + PTHREAD_SET_STATE(pthread, PS_RUNNING); + + /* Return the signal number: */ + pthread->signo = sig; + } + else { + /* + * Mark the thread as interrupted only if the + * restart flag is not set on the signal action: + */ + if (restart == 0) + pthread->interrupted = 1; + PTHREAD_WAITQ_REMOVE(pthread); + PTHREAD_SET_STATE(pthread, PS_RUNNING); + } + break; + + /* + * States which cannot be interrupted but still require the + * signal handler to run: + */ + case PS_COND_WAIT: + case PS_MUTEX_WAIT: + /* + * Remove the thread from the wait queue. It will + * be added back to the wait queue once all signal + * handlers have been invoked. + */ + PTHREAD_WAITQ_REMOVE(pthread); + break; + + case PS_JOIN: + /* + * Remove the thread from the wait queue. It will + * be added back to the wait queue once all signal + * handlers have been invoked. + */ + PTHREAD_WAITQ_REMOVE(pthread); + /* Make the thread runnable: */ + PTHREAD_SET_STATE(pthread, PS_RUNNING); + break; + + /* + * States which are interruptible but may need to be removed + * from queues before any signal handler is called. + * + * XXX - We may not need to handle this condition, but will + * mark it as a potential problem. + */ + case PS_FDLR_WAIT: + case PS_FDLW_WAIT: + case PS_FILE_WAIT: + if (restart == 0) + pthread->interrupted = 1; + /* + * Remove the thread from the wait queue. Our + * signal handler hook will remove this thread + * from the fd or file queue before invoking + * the actual handler. + */ + PTHREAD_WAITQ_REMOVE(pthread); + break; + + /* + * States which are interruptible: + */ + case PS_FDR_WAIT: + case PS_FDW_WAIT: + if (restart == 0) { + /* + * Flag the operation as interrupted and + * set the state to running: + */ + pthread->interrupted = 1; + PTHREAD_SET_STATE(pthread, PS_RUNNING); + } + PTHREAD_WORKQ_REMOVE(pthread); + PTHREAD_WAITQ_REMOVE(pthread); + break; + + case PS_POLL_WAIT: + case PS_SELECT_WAIT: + case PS_SLEEP_WAIT: + /* + * Unmasked signals always cause poll, select, and sleep + * to terminate early, regardless of SA_RESTART: + */ + pthread->interrupted = 1; + /* Remove threads in poll and select from the workq: */ + if ((pthread->flags & PTHREAD_FLAGS_IN_WORKQ) != 0) + PTHREAD_WORKQ_REMOVE(pthread); + PTHREAD_WAITQ_REMOVE(pthread); + PTHREAD_SET_STATE(pthread, PS_RUNNING); + break; + + case PS_SIGSUSPEND: + PTHREAD_WAITQ_REMOVE(pthread); + PTHREAD_SET_STATE(pthread, PS_RUNNING); + break; + } + + if (suppress_handler == 0) { + /* Setup a signal frame and save the current threads state: */ + thread_sigframe_add(pthread, sig, has_args); + + /* + * Signals are deferred until just before the threads + * signal handler is invoked: + */ + pthread->sig_defer_count = 1; + + /* Make sure the thread is runnable: */ + if (pthread->state != PS_RUNNING) + PTHREAD_SET_STATE(pthread, PS_RUNNING); + /* + * The thread should be removed from all scheduling + * queues at this point. Raise the priority and place + * the thread in the run queue. + */ + pthread->active_priority |= PTHREAD_SIGNAL_PRIORITY; + if (thread_is_active == 0) + PTHREAD_PRIOQ_INSERT_TAIL(pthread); + } +} + +static void +thread_sig_check_state(struct pthread *pthread, int sig) +{ + /* + * Process according to thread state: + */ + switch (pthread->state) { + /* + * States which do not change when a signal is trapped: + */ + case PS_DEAD: + case PS_DEADLOCK: + case PS_STATE_MAX: + case PS_SIGTHREAD: + case PS_RUNNING: + case PS_SUSPENDED: + case PS_SPINBLOCK: + case PS_COND_WAIT: + case PS_JOIN: + case PS_MUTEX_WAIT: + break; + + case PS_SIGWAIT: + /* Wake up the thread if the signal is blocked. */ + if (sigismember(pthread->data.sigwait, sig)) { + /* Change the state of the thread to run: */ + PTHREAD_NEW_STATE(pthread, PS_RUNNING); + + /* Return the signal number: */ + pthread->signo = sig; + } else + /* Increment the pending signal count. */ + sigaddset(&pthread->sigpend, sig); + break; + + /* + * The wait state is a special case due to the handling of + * SIGCHLD signals. + */ + case PS_WAIT_WAIT: + if (sig == SIGCHLD) { + /* + * Remove the thread from the wait queue and + * make it runnable: + */ + PTHREAD_NEW_STATE(pthread, PS_RUNNING); + + /* Return the signal number: */ + pthread->signo = sig; + } + break; + + case PS_FDLR_WAIT: + case PS_FDLW_WAIT: + case PS_SIGSUSPEND: + case PS_SLEEP_WAIT: + /* + * Remove the thread from the wait queue and make it + * runnable: + */ + PTHREAD_NEW_STATE(pthread, PS_RUNNING); + + /* Flag the operation as interrupted: */ + pthread->interrupted = 1; + break; + + /* + * These states are additionally in the work queue: + */ + case PS_FDR_WAIT: + case PS_FDW_WAIT: + case PS_FILE_WAIT: + case PS_POLL_WAIT: + case PS_SELECT_WAIT: + /* + * Remove the thread from the wait and work queues, and + * make it runnable: + */ + PTHREAD_WORKQ_REMOVE(pthread); + PTHREAD_NEW_STATE(pthread, PS_RUNNING); + + /* Flag the operation as interrupted: */ + pthread->interrupted = 1; + break; + } +} + +/* + * Send a signal to a specific thread (ala pthread_kill): + */ +void +_thread_sig_send(struct pthread *pthread, int sig) +{ + struct pthread *curthread = _get_curthread(); + + /* Check for signals whose actions are SIG_DFL: */ + if (_thread_sigact[sig - 1].sa_handler == SIG_DFL) { + /* + * Check to see if a temporary signal handler is + * installed for sigwaiters: + */ + if (_thread_dfl_count[sig] == 0) + /* + * Deliver the signal to the process if a handler + * is not installed: + */ + kill(getpid(), sig); + /* + * Assuming we're still running after the above kill(), + * make any necessary state changes to the thread: + */ + thread_sig_check_state(pthread, sig); + } + /* + * Check that the signal is not being ignored: + */ + else if (_thread_sigact[sig - 1].sa_handler != SIG_IGN) { + if (pthread->state == PS_SIGWAIT && + sigismember(pthread->data.sigwait, sig)) { + /* Change the state of the thread to run: */ + PTHREAD_NEW_STATE(pthread, PS_RUNNING); + + /* Return the signal number: */ + pthread->signo = sig; + } else if (sigismember(&pthread->sigmask, sig)) + /* Add the signal to the pending set: */ + sigaddset(&pthread->sigpend, sig); + else if (pthread == curthread) + /* Call the signal handler for the current thread: */ + thread_sig_invoke_handler(sig, NULL, NULL); + else { + /* Protect the scheduling queues: */ + _thread_kern_sig_defer(); + /* + * Perform any state changes due to signal + * arrival: + */ + thread_sig_add(pthread, sig, /* has args */ 0); + /* Unprotect the scheduling queues: */ + _thread_kern_sig_undefer(); + } + } +} + +/* + * User thread signal handler wrapper. + * + * thread - current running thread + */ +void +_thread_sig_wrapper(void) +{ + struct pthread_signal_frame *psf; + struct pthread *thread = _get_curthread(); + + /* Get the current frame and state: */ + psf = thread->curframe; + thread->curframe = NULL; + PTHREAD_ASSERT(psf != NULL, "Invalid signal frame in signal handler"); + + /* + * We're coming from the kernel scheduler; clear the in + * scheduler flag: + */ + _thread_kern_in_sched = 0; + + /* Check the threads previous state: */ + if (psf->saved_state.psd_state != PS_RUNNING) { + /* + * Do a little cleanup handling for those threads in + * queues before calling the signal handler. Signals + * for these threads are temporarily blocked until + * after cleanup handling. + */ + switch (psf->saved_state.psd_state) { + case PS_FDLR_WAIT: + case PS_FDLW_WAIT: + _fd_lock_backout(thread); + psf->saved_state.psd_state = PS_RUNNING; + break; + + case PS_COND_WAIT: + _cond_wait_backout(thread); + psf->saved_state.psd_state = PS_RUNNING; + break; + + case PS_MUTEX_WAIT: + _mutex_lock_backout(thread); + psf->saved_state.psd_state = PS_RUNNING; + break; + + default: + break; + } + } + + /* Unblock the signal in case we don't return from the handler: */ + _thread_sigq[psf->signo - 1].blocked = 0; + + /* + * Lower the priority before calling the handler in case + * it never returns (longjmps back): + */ + thread->active_priority &= ~PTHREAD_SIGNAL_PRIORITY; + + /* + * Reenable interruptions without checking for the need to + * context switch: + */ + thread->sig_defer_count = 0; + + /* + * Dispatch the signal via the custom signal handler: + */ + if (psf->sig_has_args == 0) + thread_sig_invoke_handler(psf->signo, NULL, NULL); + else + thread_sig_invoke_handler(psf->signo, &psf->siginfo, &psf->uc); + + /* + * Call the kernel scheduler to safely restore the frame and + * schedule the next thread: + */ + _thread_kern_sched_frame(psf); +} + +static void +thread_sigframe_add(struct pthread *thread, int sig, int has_args) +{ + struct pthread_signal_frame *psf = NULL; + unsigned long stackp; + + /* Get the top of the threads stack: */ + stackp = GET_STACK_JB(thread->ctx.jb); + + /* + * Leave a little space on the stack and round down to the + * nearest aligned word: + */ + stackp -= sizeof(double); + stackp &= ~0x3UL; + + /* Allocate room on top of the stack for a new signal frame: */ + stackp -= sizeof(struct pthread_signal_frame); + + psf = (struct pthread_signal_frame *) stackp; + + /* Save the current context in the signal frame: */ + thread_sigframe_save(thread, psf); + + /* Set handler specific information: */ + psf->sig_has_args = has_args; + psf->signo = sig; + if (has_args) { + /* Copy the signal handler arguments to the signal frame: */ + memcpy(&psf->uc, &_thread_sigq[psf->signo - 1].uc, + sizeof(psf->uc)); + memcpy(&psf->siginfo, &_thread_sigq[psf->signo - 1].siginfo, + sizeof(psf->siginfo)); + } + + /* Setup the signal mask: */ + SIGSETOR(thread->sigmask, _thread_sigact[sig - 1].sa_mask); + sigaddset(&thread->sigmask, sig); + + /* Set up the new frame: */ + thread->curframe = psf; + thread->flags &= PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE | + PTHREAD_FLAGS_IN_SYNCQ; + /* + * Set up the context: + */ + stackp -= sizeof(double); + _setjmp(thread->ctx.jb); + SET_STACK_JB(thread->ctx.jb, stackp); + SET_RETURN_ADDR_JB(thread->ctx.jb, _thread_sig_wrapper); +} + +void +_thread_sigframe_restore(struct pthread *thread, + struct pthread_signal_frame *psf) +{ + memcpy(&thread->ctx, &psf->ctx, sizeof(thread->ctx)); + /* + * Only restore the signal mask if it hasn't been changed + * by the application during invocation of the signal handler: + */ + if (thread->sigmask_seqno == psf->saved_state.psd_sigmask_seqno) + thread->sigmask = psf->saved_state.psd_sigmask; + thread->curframe = psf->saved_state.psd_curframe; + thread->wakeup_time = psf->saved_state.psd_wakeup_time; + thread->data = psf->saved_state.psd_wait_data; + thread->state = psf->saved_state.psd_state; + thread->flags = psf->saved_state.psd_flags; + thread->interrupted = psf->saved_state.psd_interrupted; + thread->signo = psf->saved_state.psd_signo; + thread->sig_defer_count = psf->saved_state.psd_sig_defer_count; +} + +static void +thread_sigframe_save(struct pthread *thread, struct pthread_signal_frame *psf) +{ + memcpy(&psf->ctx, &thread->ctx, sizeof(thread->ctx)); + psf->saved_state.psd_sigmask = thread->sigmask; + psf->saved_state.psd_curframe = thread->curframe; + psf->saved_state.psd_wakeup_time = thread->wakeup_time; + psf->saved_state.psd_wait_data = thread->data; + psf->saved_state.psd_state = thread->state; + psf->saved_state.psd_flags = thread->flags & + (PTHREAD_FLAGS_PRIVATE | PTHREAD_FLAGS_TRACE); + psf->saved_state.psd_interrupted = thread->interrupted; + psf->saved_state.psd_sigmask_seqno = thread->sigmask_seqno; + psf->saved_state.psd_signo = thread->signo; + psf->saved_state.psd_sig_defer_count = thread->sig_defer_count; +} + diff --git a/lib/libc_r/uthread/uthread_sigaction.c b/lib/libc_r/uthread/uthread_sigaction.c new file mode 100644 index 0000000..2be587c --- /dev/null +++ b/lib/libc_r/uthread/uthread_sigaction.c @@ -0,0 +1,112 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <signal.h> +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_sigaction, sigaction); + +int +_sigaction(int sig, const struct sigaction * act, struct sigaction * oact) +{ + int ret = 0; + struct sigaction gact; + + /* Check if the signal number is out of range: */ + if (sig < 1 || sig > NSIG) { + /* Return an invalid argument: */ + errno = EINVAL; + ret = -1; + } else { + if (_thread_initial == NULL) + _thread_init(); + + /* + * Check if the existing signal action structure contents are + * to be returned: + */ + if (oact != NULL) { + /* Return the existing signal action contents: */ + oact->sa_handler = _thread_sigact[sig - 1].sa_handler; + oact->sa_mask = _thread_sigact[sig - 1].sa_mask; + oact->sa_flags = _thread_sigact[sig - 1].sa_flags; + } + + /* Check if a signal action was supplied: */ + if (act != NULL) { + /* Set the new signal handler: */ + _thread_sigact[sig - 1].sa_mask = act->sa_mask; + _thread_sigact[sig - 1].sa_flags = act->sa_flags; + _thread_sigact[sig - 1].sa_handler = act->sa_handler; + } + + /* + * Check if the kernel needs to be advised of a change + * in signal action: + */ + if (act != NULL && sig != _SCHED_SIGNAL && sig != SIGCHLD && + sig != SIGINFO) { + /* + * Ensure the signal handler cannot be interrupted + * by other signals. Always request the POSIX signal + * handler arguments. + */ + sigfillset(&gact.sa_mask); + gact.sa_flags = SA_SIGINFO | SA_ONSTACK; + + /* + * Check if the signal handler is being set to + * the default or ignore handlers: + */ + if (act->sa_handler == SIG_DFL || + act->sa_handler == SIG_IGN) + /* Specify the built in handler: */ + gact.sa_handler = act->sa_handler; + else + /* + * Specify the thread kernel signal + * handler: + */ + gact.sa_handler = (void (*) ()) _thread_sig_handler; + + /* Change the signal action in the kernel: */ + if (__sys_sigaction(sig,&gact,NULL) != 0) + ret = -1; + } + } + + /* Return the completion status: */ + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_sigmask.c b/lib/libc_r/uthread/uthread_sigmask.c new file mode 100644 index 0000000..040e7aa --- /dev/null +++ b/lib/libc_r/uthread/uthread_sigmask.c @@ -0,0 +1,106 @@ +/* + * Copyright (c) 1997 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <sys/param.h> +#include <sys/types.h> +#include <sys/signalvar.h> +#include <errno.h> +#include <signal.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_sigmask, pthread_sigmask); + +int +_pthread_sigmask(int how, const sigset_t *set, sigset_t *oset) +{ + struct pthread *curthread = _get_curthread(); + sigset_t sigset; + int ret = 0; + + /* Check if the existing signal process mask is to be returned: */ + if (oset != NULL) { + /* Return the current mask: */ + *oset = curthread->sigmask; + } + /* Check if a new signal set was provided by the caller: */ + if (set != NULL) { + /* Process according to what to do: */ + switch (how) { + /* Block signals: */ + case SIG_BLOCK: + /* Add signals to the existing mask: */ + SIGSETOR(curthread->sigmask, *set); + break; + + /* Unblock signals: */ + case SIG_UNBLOCK: + /* Clear signals from the existing mask: */ + SIGSETNAND(curthread->sigmask, *set); + break; + + /* Set the signal process mask: */ + case SIG_SETMASK: + /* Set the new mask: */ + curthread->sigmask = *set; + break; + + /* Trap invalid actions: */ + default: + /* Return an invalid argument: */ + errno = EINVAL; + ret = -1; + break; + } + + /* Increment the sequence number: */ + curthread->sigmask_seqno++; + + /* + * Check if there are pending signals for the running + * thread or process that aren't blocked: + */ + sigset = curthread->sigpend; + SIGSETOR(sigset, _process_sigpending); + SIGSETNAND(sigset, curthread->sigmask); + if (SIGNOTEMPTY(sigset)) + /* + * Call the kernel scheduler which will safely + * install a signal frame for the running thread: + */ + _thread_kern_sched_sig(); + } + + /* Return the completion status: */ + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_sigpending.c b/lib/libc_r/uthread/uthread_sigpending.c new file mode 100644 index 0000000..3c7efa4 --- /dev/null +++ b/lib/libc_r/uthread/uthread_sigpending.c @@ -0,0 +1,57 @@ +/* + * Copyright (c) 1999 Daniel Eischen <eischen@vigrid.com>. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <signal.h> +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_sigpending, sigpending); + +int +_sigpending(sigset_t * set) +{ + struct pthread *curthread = _get_curthread(); + int ret = 0; + + /* Check for a null signal set pointer: */ + if (set == NULL) { + /* Return an invalid argument: */ + ret = EINVAL; + } + else { + *set = curthread->sigpend; + } + /* Return the completion status: */ + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_sigprocmask.c b/lib/libc_r/uthread/uthread_sigprocmask.c new file mode 100644 index 0000000..cc0b8da --- /dev/null +++ b/lib/libc_r/uthread/uthread_sigprocmask.c @@ -0,0 +1,48 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <sys/param.h> +#include <sys/types.h> +#include <sys/signalvar.h> +#include <signal.h> +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_sigprocmask, sigprocmask); + +int +_sigprocmask(int how, const sigset_t *set, sigset_t *oset) +{ + return (pthread_sigmask(how, set, oset)); +} diff --git a/lib/libc_r/uthread/uthread_sigsuspend.c b/lib/libc_r/uthread/uthread_sigsuspend.c new file mode 100644 index 0000000..1201097 --- /dev/null +++ b/lib/libc_r/uthread/uthread_sigsuspend.c @@ -0,0 +1,83 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <signal.h> +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(__sigsuspend, sigsuspend); + +int +_sigsuspend(const sigset_t * set) +{ + struct pthread *curthread = _get_curthread(); + int ret = -1; + sigset_t oset; + + /* Check if a new signal set was provided by the caller: */ + if (set != NULL) { + /* Save the current signal mask: */ + oset = curthread->sigmask; + + /* Change the caller's mask: */ + curthread->sigmask = *set; + + /* Wait for a signal: */ + _thread_kern_sched_state(PS_SIGSUSPEND, __FILE__, __LINE__); + + /* Always return an interrupted error: */ + errno = EINTR; + + /* Restore the signal mask: */ + curthread->sigmask = oset; + } else { + /* Return an invalid argument error: */ + errno = EINVAL; + } + + /* Return the completion status: */ + return (ret); +} + +int +__sigsuspend(const sigset_t * set) +{ + int ret; + + _thread_enter_cancellation_point(); + ret = _sigsuspend(set); + _thread_leave_cancellation_point(); + + return ret; +} diff --git a/lib/libc_r/uthread/uthread_sigwait.c b/lib/libc_r/uthread/uthread_sigwait.c new file mode 100644 index 0000000..1e87249 --- /dev/null +++ b/lib/libc_r/uthread/uthread_sigwait.c @@ -0,0 +1,174 @@ +/* + * Copyright (c) 1997 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <signal.h> +#include <sys/param.h> +#include <sys/signalvar.h> +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_sigwait, sigwait); + +int +_sigwait(const sigset_t *set, int *sig) +{ + struct pthread *curthread = _get_curthread(); + int ret = 0; + int i; + sigset_t tempset, waitset; + struct sigaction act; + + _thread_enter_cancellation_point(); + /* + * Specify the thread kernel signal handler. + */ + act.sa_handler = (void (*) ()) _thread_sig_handler; + act.sa_flags = SA_RESTART | SA_SIGINFO; + /* Ensure the signal handler cannot be interrupted by other signals: */ + sigfillset(&act.sa_mask); + + /* + * Initialize the set of signals that will be waited on: + */ + waitset = *set; + + /* These signals can't be waited on. */ + sigdelset(&waitset, SIGKILL); + sigdelset(&waitset, SIGSTOP); + sigdelset(&waitset, _SCHED_SIGNAL); + sigdelset(&waitset, SIGCHLD); + sigdelset(&waitset, SIGINFO); + + /* Check to see if a pending signal is in the wait mask. */ + tempset = curthread->sigpend; + SIGSETOR(tempset, _process_sigpending); + SIGSETAND(tempset, waitset); + if (SIGNOTEMPTY(tempset)) { + /* Enter a loop to find a pending signal: */ + for (i = 1; i < NSIG; i++) { + if (sigismember (&tempset, i)) + break; + } + + /* Clear the pending signal: */ + if (sigismember(&curthread->sigpend,i)) + sigdelset(&curthread->sigpend,i); + else + sigdelset(&_process_sigpending,i); + + /* Return the signal number to the caller: */ + *sig = i; + + _thread_leave_cancellation_point(); + return (0); + } + + /* + * Access the _thread_dfl_count array under the protection of signal + * deferral. + */ + _thread_kern_sig_defer(); + + /* + * Enter a loop to find the signals that are SIG_DFL. For + * these signals we must install a dummy signal handler in + * order for the kernel to pass them in to us. POSIX says + * that the _application_ must explicitly install a dummy + * handler for signals that are SIG_IGN in order to sigwait + * on them. Note that SIG_IGN signals are left in the + * mask because a subsequent sigaction could enable an + * ignored signal. + */ + sigemptyset(&tempset); + for (i = 1; i < NSIG; i++) { + if (sigismember(&waitset, i) && + (_thread_sigact[i - 1].sa_handler == SIG_DFL)) { + _thread_dfl_count[i]++; + sigaddset(&tempset, i); + if (_thread_dfl_count[i] == 1) { + if (__sys_sigaction(i,&act,NULL) != 0) + ret = -1; + } + } + } + /* Done accessing _thread_dfl_count for now. */ + _thread_kern_sig_undefer(); + + if (ret == 0) { + /* + * Save the wait signal mask. The wait signal + * mask is independent of the threads signal mask + * and requires separate storage. + */ + curthread->data.sigwait = &waitset; + + /* Wait for a signal: */ + _thread_kern_sched_state(PS_SIGWAIT, __FILE__, __LINE__); + + /* Return the signal number to the caller: */ + *sig = curthread->signo; + + /* + * Probably unnecessary, but since it's in a union struct + * we don't know how it could be used in the future. + */ + curthread->data.sigwait = NULL; + } + + /* + * Access the _thread_dfl_count array under the protection of signal + * deferral. + */ + _thread_kern_sig_defer(); + + /* Restore the sigactions: */ + act.sa_handler = SIG_DFL; + for (i = 1; i < NSIG; i++) { + if (sigismember(&tempset, i)) { + _thread_dfl_count[i]--; + if ((_thread_sigact[i - 1].sa_handler == SIG_DFL) && + (_thread_dfl_count[i] == 0)) { + if (__sys_sigaction(i,&act,NULL) != 0) + ret = -1; + } + } + } + /* Done accessing _thread_dfl_count. */ + _thread_kern_sig_undefer(); + + _thread_leave_cancellation_point(); + + /* Return the completion status: */ + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_single_np.c b/lib/libc_r/uthread/uthread_single_np.c new file mode 100644 index 0000000..85471b8 --- /dev/null +++ b/lib/libc_r/uthread/uthread_single_np.c @@ -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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <string.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_pthread_single_np, pthread_single_np); + +int _pthread_single_np() +{ + struct pthread *curthread = _get_curthread(); + + /* Enter single-threaded (non-POSIX) scheduling mode: */ + _thread_single = curthread; + return(0); +} diff --git a/lib/libc_r/uthread/uthread_sleep.c b/lib/libc_r/uthread/uthread_sleep.c new file mode 100644 index 0000000..9e09db7 --- /dev/null +++ b/lib/libc_r/uthread/uthread_sleep.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. + * 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(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) 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. + * + * $FreeBSD$ + */ + +#include <unistd.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_sleep, sleep); + +unsigned int +_sleep(unsigned int seconds) +{ + unsigned int ret; + + _thread_enter_cancellation_point(); + ret = __sleep(seconds); + _thread_leave_cancellation_point(); + + return ret; +} diff --git a/lib/libc_r/uthread/uthread_socket.c b/lib/libc_r/uthread/uthread_socket.c new file mode 100644 index 0000000..28b5a72 --- /dev/null +++ b/lib/libc_r/uthread/uthread_socket.c @@ -0,0 +1,58 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <sys/types.h> +#include <sys/socket.h> +#include <fcntl.h> +#include <unistd.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_socket, socket); + +int +_socket(int af, int type, int protocol) +{ + int fd; + + /* Create a socket: */ + if ((fd = __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) { + __sys_close(fd); + fd = -1; + } + return (fd); +} diff --git a/lib/libc_r/uthread/uthread_socketpair.c b/lib/libc_r/uthread/uthread_socketpair.c new file mode 100644 index 0000000..6cd9cb6 --- /dev/null +++ b/lib/libc_r/uthread/uthread_socketpair.c @@ -0,0 +1,56 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + * + */ +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <fcntl.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_socketpair, socketpair); + +int +_socketpair(int af, int type, int protocol, int pair[2]) +{ + int ret; + if (!((ret = __sys_socketpair(af, type, protocol, pair)) < 0)) + if (_thread_fd_table_init(pair[0]) != 0 || + _thread_fd_table_init(pair[1]) != 0) { + __sys_close(pair[0]); + __sys_close(pair[1]); + ret = -1; + } + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_spec.c b/lib/libc_r/uthread/uthread_spec.c new file mode 100644 index 0000000..e71f75f --- /dev/null +++ b/lib/libc_r/uthread/uthread_spec.c @@ -0,0 +1,225 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +struct pthread_key { + spinlock_t lock; + volatile int allocated; + volatile int count; + int seqno; + void (*destructor) (); +}; + +/* Static variables: */ +static struct pthread_key key_table[PTHREAD_KEYS_MAX]; + +__weak_reference(_pthread_key_create, pthread_key_create); +__weak_reference(_pthread_key_delete, pthread_key_delete); +__weak_reference(_pthread_getspecific, pthread_getspecific); +__weak_reference(_pthread_setspecific, pthread_setspecific); + + +int +_pthread_key_create(pthread_key_t * key, void (*destructor) (void *)) +{ + for ((*key) = 0; (*key) < PTHREAD_KEYS_MAX; (*key)++) { + /* Lock the key table entry: */ + _SPINLOCK(&key_table[*key].lock); + + if (key_table[(*key)].allocated == 0) { + key_table[(*key)].allocated = 1; + key_table[(*key)].destructor = destructor; + key_table[(*key)].seqno++; + + /* Unlock the key table entry: */ + _SPINUNLOCK(&key_table[*key].lock); + return (0); + } + + /* Unlock the key table entry: */ + _SPINUNLOCK(&key_table[*key].lock); + } + return (EAGAIN); +} + +int +_pthread_key_delete(pthread_key_t key) +{ + int ret = 0; + + if (key < PTHREAD_KEYS_MAX) { + /* Lock the key table entry: */ + _SPINLOCK(&key_table[key].lock); + + if (key_table[key].allocated) + key_table[key].allocated = 0; + else + ret = EINVAL; + + /* Unlock the key table entry: */ + _SPINUNLOCK(&key_table[key].lock); + } else + ret = EINVAL; + return (ret); +} + +void +_thread_cleanupspecific(void) +{ + struct pthread *curthread = _get_curthread(); + void *data = NULL; + int key; + int itr; + void (*destructor)( void *); + + for (itr = 0; itr < PTHREAD_DESTRUCTOR_ITERATIONS; itr++) { + for (key = 0; key < PTHREAD_KEYS_MAX; key++) { + if (curthread->specific_data_count > 0) { + /* Lock the key table entry: */ + _SPINLOCK(&key_table[key].lock); + destructor = NULL; + + if (key_table[key].allocated && + (curthread->specific[key].data != NULL)) { + if (curthread->specific[key].seqno == + key_table[key].seqno) { + data = (void *) curthread->specific[key].data; + destructor = key_table[key].destructor; + } + curthread->specific[key].data = NULL; + curthread->specific_data_count--; + } + + /* Unlock the key table entry: */ + _SPINUNLOCK(&key_table[key].lock); + + /* + * If there is a destructore, call it + * with the key table entry unlocked: + */ + if (destructor) + destructor(data); + } else { + free(curthread->specific); + curthread->specific = NULL; + return; + } + } + } + if (curthread->specific != NULL) { + free(curthread->specific); + curthread->specific = NULL; + } +} + +static inline struct pthread_specific_elem * +pthread_key_allocate_data(void) +{ + struct pthread_specific_elem *new_data; + + new_data = (struct pthread_specific_elem *) + malloc(sizeof(struct pthread_specific_elem) * PTHREAD_KEYS_MAX); + if (new_data != NULL) { + memset((void *) new_data, 0, + sizeof(struct pthread_specific_elem) * PTHREAD_KEYS_MAX); + } + return (new_data); +} + +int +_pthread_setspecific(pthread_key_t key, const void *value) +{ + struct pthread *pthread; + int ret = 0; + + /* Point to the running thread: */ + pthread = _get_curthread(); + + if ((pthread->specific) || + (pthread->specific = pthread_key_allocate_data())) { + if (key < PTHREAD_KEYS_MAX) { + if (key_table[key].allocated) { + if (pthread->specific[key].data == NULL) { + if (value != NULL) + pthread->specific_data_count++; + } else { + if (value == NULL) + pthread->specific_data_count--; + } + pthread->specific[key].data = value; + pthread->specific[key].seqno = + key_table[key].seqno; + ret = 0; + } else + ret = EINVAL; + } else + ret = EINVAL; + } else + ret = ENOMEM; + return (ret); +} + +void * +_pthread_getspecific(pthread_key_t key) +{ + struct pthread *pthread; + void *data; + + /* Point to the running thread: */ + pthread = _get_curthread(); + + /* Check if there is specific data: */ + if (pthread->specific != NULL && key < PTHREAD_KEYS_MAX) { + /* Check if this key has been used before: */ + if (key_table[key].allocated && + (pthread->specific[key].seqno == key_table[key].seqno)) { + /* Return the value: */ + data = (void *) pthread->specific[key].data; + } else { + /* + * This key has not been used before, so return NULL + * instead: + */ + data = NULL; + } + } else + /* No specific data has been created, so just return NULL: */ + data = NULL; + return (data); +} diff --git a/lib/libc_r/uthread/uthread_spinlock.c b/lib/libc_r/uthread/uthread_spinlock.c new file mode 100644 index 0000000..7333709 --- /dev/null +++ b/lib/libc_r/uthread/uthread_spinlock.c @@ -0,0 +1,111 @@ +/* + * Copyright (c) 1997 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 AUTHOR 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. + * + * $FreeBSD$ + * + */ + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <sched.h> +#include <pthread.h> +#include <unistd.h> + +#include <libc_private.h> + +#include "pthread_private.h" + +/* + * Lock a location for the running thread. Yield to allow other + * threads to run if this thread is blocked because the lock is + * not available. Note that this function does not sleep. It + * assumes that the lock will be available very soon. + */ +void +_spinlock(spinlock_t *lck) +{ + struct pthread *curthread = _get_curthread(); + + /* + * Try to grab the lock and loop if another thread grabs + * it before we do. + */ + while(_atomic_lock(&lck->access_lock)) { + /* Block the thread until the lock. */ + curthread->data.spinlock = lck; + _thread_kern_sched_state(PS_SPINBLOCK, __FILE__, __LINE__); + } + + /* The running thread now owns the lock: */ + lck->lock_owner = (long) curthread; +} + +/* + * Lock a location for the running thread. Yield to allow other + * threads to run if this thread is blocked because the lock is + * not available. Note that this function does not sleep. It + * assumes that the lock will be available very soon. + * + * This function checks if the running thread has already locked the + * location, warns if this occurs and creates a thread dump before + * returning. + */ +void +_spinlock_debug(spinlock_t *lck, char *fname, int lineno) +{ + struct pthread *curthread = _get_curthread(); + int cnt = 0; + + /* + * Try to grab the lock and loop if another thread grabs + * it before we do. + */ + while(_atomic_lock(&lck->access_lock)) { + cnt++; + if (cnt > 100) { + char str[256]; + snprintf(str, sizeof(str), "%s - Warning: Thread %p attempted to lock %p from %s (%d) was left locked from %s (%d)\n", _getprogname(), curthread, lck, fname, lineno, lck->fname, lck->lineno); + __sys_write(2,str,strlen(str)); + __sleep(1); + cnt = 0; + } + + /* Block the thread until the lock. */ + curthread->data.spinlock = lck; + _thread_kern_sched_state(PS_SPINBLOCK, fname, lineno); + } + + /* The running thread now owns the lock: */ + lck->lock_owner = (long) curthread; + lck->fname = fname; + lck->lineno = lineno; +} diff --git a/lib/libc_r/uthread/uthread_stack.c b/lib/libc_r/uthread/uthread_stack.c new file mode 100644 index 0000000..86f0a2d --- /dev/null +++ b/lib/libc_r/uthread/uthread_stack.c @@ -0,0 +1,237 @@ +/* + * Copyright (c) 2001 Daniel Eischen <deischen@freebsd.org> + * Copyright (c) 2000-2001 Jason Evans <jasone@freebsd.org> + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHORS 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 AUTHORS 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. + * + * $FreeBSD$ + */ +#include <sys/types.h> +#include <sys/mman.h> +#include <sys/param.h> +#include <sys/queue.h> +#include <sys/user.h> +#include <stdlib.h> +#include <pthread.h> +#include "pthread_private.h" + +/* Spare thread stack. */ +struct stack { + LIST_ENTRY(stack) qe; /* Stack queue linkage. */ + size_t stacksize; /* Stack size (rounded up). */ + size_t guardsize; /* Guard size. */ + void *stackaddr; /* Stack address. */ +}; + +/* + * Default sized (stack and guard) spare stack queue. Stacks are cached to + * avoid additional complexity managing mmap()ed stack regions. Spare stacks + * are used in LIFO order to increase cache locality. + */ +static LIST_HEAD(, stack) _dstackq = LIST_HEAD_INITIALIZER(_dstackq); + +/* + * Miscellaneous sized (non-default stack and/or guard) spare stack queue. + * Stacks are cached to avoid additional complexity managing mmap()ed stack + * regions. This list is unordered, since ordering on both stack size and guard + * size would be more trouble than it's worth. Stacks are allocated from this + * cache on a first size match basis. + */ +static LIST_HEAD(, stack) _mstackq = LIST_HEAD_INITIALIZER(_mstackq); + +/** + * Base address of the last stack allocated (including its red zone, if there is + * one). Stacks are allocated contiguously, starting beyond the top of the main + * stack. When a new stack is created, a red zone is typically created + * (actually, the red zone is simply left unmapped) above the top of the stack, + * such that the stack will not be able to grow all the way to the bottom of the + * next stack. This isn't fool-proof. It is possible for a stack to grow by a + * large amount, such that it grows into the next stack, and as long as the + * memory within the red zone is never accessed, nothing will prevent one thread + * stack from trouncing all over the next. + * + * low memory + * . . . . . . . . . . . . . . . . . . + * | | + * | stack 3 | start of 3rd thread stack + * +-----------------------------------+ + * | | + * | Red Zone (guard page) | red zone for 2nd thread + * | | + * +-----------------------------------+ + * | stack 2 - PTHREAD_STACK_DEFAULT | top of 2nd thread stack + * | | + * | | + * | | + * | | + * | stack 2 | + * +-----------------------------------+ <-- start of 2nd thread stack + * | | + * | Red Zone | red zone for 1st thread + * | | + * +-----------------------------------+ + * | stack 1 - PTHREAD_STACK_DEFAULT | top of 1st thread stack + * | | + * | | + * | | + * | | + * | stack 1 | + * +-----------------------------------+ <-- start of 1st thread stack + * | | (initial value of last_stack) + * | Red Zone | + * | | red zone for main thread + * +-----------------------------------+ + * | USRSTACK - PTHREAD_STACK_INITIAL | top of main thread stack + * | | ^ + * | | | + * | | | + * | | | stack growth + * | | + * +-----------------------------------+ <-- start of main thread stack + * (USRSTACK) + * high memory + * + */ +static void * last_stack; + +void * +_thread_stack_alloc(size_t stacksize, size_t guardsize) +{ + void *stack = NULL; + struct stack *spare_stack; + size_t stack_size; + + /* + * Round up stack size to nearest multiple of PAGE_SIZE, so that mmap() + * will work. If the stack size is not an even multiple, we end up + * initializing things such that there is unused space above the + * beginning of the stack, so the stack sits snugly against its guard. + */ + if (stacksize % PAGE_SIZE != 0) + stack_size = ((stacksize / PAGE_SIZE) + 1) * PAGE_SIZE; + else + stack_size = stacksize; + + /* + * If the stack and guard sizes are default, try to allocate a stack + * from the default-size stack cache: + */ + if (stack_size == PTHREAD_STACK_DEFAULT && + guardsize == PTHREAD_GUARD_DEFAULT) { + /* + * Use the garbage collector mutex for synchronization of the + * spare stack list. + */ + if (pthread_mutex_lock(&_gc_mutex) != 0) + PANIC("Cannot lock gc mutex"); + + if ((spare_stack = LIST_FIRST(&_dstackq)) != NULL) { + /* Use the spare stack. */ + LIST_REMOVE(spare_stack, qe); + stack = spare_stack->stackaddr; + } + + /* Unlock the garbage collector mutex. */ + if (pthread_mutex_unlock(&_gc_mutex) != 0) + PANIC("Cannot unlock gc mutex"); + } + /* + * The user specified a non-default stack and/or guard size, so try to + * allocate a stack from the non-default size stack cache, using the + * rounded up stack size (stack_size) in the search: + */ + else { + /* + * Use the garbage collector mutex for synchronization of the + * spare stack list. + */ + if (pthread_mutex_lock(&_gc_mutex) != 0) + PANIC("Cannot lock gc mutex"); + + LIST_FOREACH(spare_stack, &_mstackq, qe) { + if (spare_stack->stacksize == stack_size && + spare_stack->guardsize == guardsize) { + LIST_REMOVE(spare_stack, qe); + stack = spare_stack->stackaddr; + break; + } + } + + /* Unlock the garbage collector mutex. */ + if (pthread_mutex_unlock(&_gc_mutex) != 0) + PANIC("Cannot unlock gc mutex"); + } + + /* Check if a stack was not allocated from a stack cache: */ + if (stack == NULL) { + + if (last_stack == NULL) + last_stack = _usrstack - PTHREAD_STACK_INITIAL - + PTHREAD_GUARD_DEFAULT; + + /* Allocate a new stack. */ + stack = last_stack - stack_size; + + /* + * Even if stack allocation fails, we don't want to try to use + * this location again, so unconditionally decrement + * last_stack. Under normal operating conditions, the most + * likely reason for an mmap() error is a stack overflow of the + * adjacent thread stack. + */ + last_stack -= (stack_size + guardsize); + + /* Stack: */ + if (mmap(stack, stack_size, PROT_READ | PROT_WRITE, MAP_STACK, + -1, 0) == MAP_FAILED) + stack = NULL; + } + + return (stack); +} + +/* This function must be called with _gc_mutex held. */ +void +_thread_stack_free(void *stack, size_t stacksize, size_t guardsize) +{ + struct stack *spare_stack; + + spare_stack = (stack + stacksize - sizeof(struct stack)); + /* Round stacksize up to nearest multiple of PAGE_SIZE. */ + if (stacksize % PAGE_SIZE != 0) { + spare_stack->stacksize = ((stacksize / PAGE_SIZE) + 1) * + PAGE_SIZE; + } else + spare_stack->stacksize = stacksize; + spare_stack->guardsize = guardsize; + spare_stack->stackaddr = stack; + + if (spare_stack->stacksize == PTHREAD_STACK_DEFAULT && + spare_stack->guardsize == PTHREAD_GUARD_DEFAULT) { + /* Default stack/guard size. */ + LIST_INSERT_HEAD(&_dstackq, spare_stack, qe); + } else { + /* Non-default stack/guard size. */ + LIST_INSERT_HEAD(&_mstackq, spare_stack, qe); + } +} diff --git a/lib/libc_r/uthread/uthread_suspend_np.c b/lib/libc_r/uthread/uthread_suspend_np.c new file mode 100644 index 0000000..0e272ff --- /dev/null +++ b/lib/libc_r/uthread/uthread_suspend_np.c @@ -0,0 +1,161 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <pthread.h> +#include "pthread_private.h" + +static void finish_suspension(void *arg); + +__weak_reference(_pthread_suspend_np, pthread_suspend_np); + +/* Suspend a thread: */ +int +_pthread_suspend_np(pthread_t thread) +{ + int ret; + + /* Find the thread in the list of active threads: */ + if ((ret = _find_thread(thread)) == 0) { + /* + * Defer signals to protect the scheduling queues from + * access by the signal handler: + */ + _thread_kern_sig_defer(); + + switch (thread->state) { + case PS_RUNNING: + /* + * Remove the thread from the priority queue and + * set the state to suspended: + */ + PTHREAD_PRIOQ_REMOVE(thread); + PTHREAD_SET_STATE(thread, PS_SUSPENDED); + break; + + case PS_SPINBLOCK: + case PS_FDR_WAIT: + case PS_FDW_WAIT: + case PS_POLL_WAIT: + case PS_SELECT_WAIT: + /* + * Remove these threads from the work queue + * and mark the operation as interrupted: + */ + if ((thread->flags & PTHREAD_FLAGS_IN_WORKQ) != 0) + PTHREAD_WORKQ_REMOVE(thread); + _thread_seterrno(thread,EINTR); + + /* FALLTHROUGH */ + case PS_SLEEP_WAIT: + thread->interrupted = 1; + + /* FALLTHROUGH */ + case PS_SIGTHREAD: + case PS_WAIT_WAIT: + case PS_SIGSUSPEND: + case PS_SIGWAIT: + /* + * Remove these threads from the waiting queue and + * set their state to suspended: + */ + PTHREAD_WAITQ_REMOVE(thread); + PTHREAD_SET_STATE(thread, PS_SUSPENDED); + break; + + case PS_MUTEX_WAIT: + /* Mark the thread as suspended and still in a queue. */ + thread->suspended = SUSP_MUTEX_WAIT; + + PTHREAD_SET_STATE(thread, PS_SUSPENDED); + break; + case PS_COND_WAIT: + /* Mark the thread as suspended and still in a queue. */ + thread->suspended = SUSP_COND_WAIT; + + PTHREAD_SET_STATE(thread, PS_SUSPENDED); + break; + case PS_JOIN: + /* Mark the thread as suspended and joining: */ + thread->suspended = SUSP_JOIN; + + PTHREAD_NEW_STATE(thread, PS_SUSPENDED); + break; + case PS_FDLR_WAIT: + case PS_FDLW_WAIT: + case PS_FILE_WAIT: + /* Mark the thread as suspended: */ + thread->suspended = SUSP_YES; + + /* + * Threads in these states may be in queues. + * In order to preserve queue integrity, the + * cancelled thread must remove itself from the + * queue. Mark the thread as interrupted and + * set the state to running. When the thread + * resumes, it will remove itself from the queue + * and call the suspension completion routine. + */ + thread->interrupted = 1; + _thread_seterrno(thread, EINTR); + PTHREAD_NEW_STATE(thread, PS_RUNNING); + thread->continuation = finish_suspension; + break; + + case PS_DEAD: + case PS_DEADLOCK: + case PS_STATE_MAX: + case PS_SUSPENDED: + /* Nothing needs to be done: */ + break; + } + + /* + * Undefer and handle pending signals, yielding if + * necessary: + */ + _thread_kern_sig_undefer(); + } + return(ret); +} + +static void +finish_suspension(void *arg) +{ + struct pthread *curthread = _get_curthread(); + + if (curthread->suspended != SUSP_NO) + _thread_kern_sched_state(PS_SUSPENDED, __FILE__, __LINE__); +} + + diff --git a/lib/libc_r/uthread/uthread_switch_np.c b/lib/libc_r/uthread/uthread_switch_np.c new file mode 100644 index 0000000..f24d99f --- /dev/null +++ b/lib/libc_r/uthread/uthread_switch_np.c @@ -0,0 +1,71 @@ +/* + * Copyright (c) 1998 Daniel Eischen <eischen@vigrid.com>. + * 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 Daniel Eischen. + * 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 DANIEL EISCHEN 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <errno.h> +#include <pthread.h> +#include <pthread_np.h> +#include "pthread_private.h" + + +__weak_reference(_pthread_switch_add_np, pthread_switch_add_np); +__weak_reference(_pthread_switch_delete_np, pthread_switch_delete_np); + +int +_pthread_switch_add_np(pthread_switch_routine_t routine) +{ + int ret = 0; + + if (routine == NULL) + /* Return an invalid argument error: */ + ret = EINVAL; + else + /* Shouldn't need a lock to protect this assigment. */ + _sched_switch_hook = routine; + + return(ret); +} + +int +_pthread_switch_delete_np(pthread_switch_routine_t routine) +{ + int ret = 0; + + if (routine != _sched_switch_hook) + /* Return an invalid argument error: */ + ret = EINVAL; + else + /* Shouldn't need a lock to protect this assigment. */ + _sched_switch_hook = NULL; + + return(ret); +} diff --git a/lib/libc_r/uthread/uthread_system.c b/lib/libc_r/uthread/uthread_system.c new file mode 100644 index 0000000..d63969b --- /dev/null +++ b/lib/libc_r/uthread/uthread_system.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. + * 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(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) 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. + * + * $FreeBSD$ + */ + +#include <stdlib.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_system, system); + +int +_system(const char *string) +{ + int ret; + + _thread_enter_cancellation_point(); + ret = __system(string); + _thread_leave_cancellation_point(); + + return ret; +} diff --git a/lib/libc_r/uthread/uthread_tcdrain.c b/lib/libc_r/uthread/uthread_tcdrain.c new file mode 100644 index 0000000..272bdf6 --- /dev/null +++ b/lib/libc_r/uthread/uthread_tcdrain.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. + * 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(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) 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. + * + * $FreeBSD$ + */ + +#include <termios.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_tcdrain, tcdrain); + +int +_tcdrain(int fd) +{ + int ret; + + _thread_enter_cancellation_point(); + ret = __tcdrain(fd); + _thread_leave_cancellation_point(); + + return ret; +} diff --git a/lib/libc_r/uthread/uthread_vfork.c b/lib/libc_r/uthread/uthread_vfork.c new file mode 100644 index 0000000..dbefc65 --- /dev/null +++ b/lib/libc_r/uthread/uthread_vfork.c @@ -0,0 +1,12 @@ +/* + * $FreeBSD$ + */ +#include <unistd.h> + +__weak_reference(_vfork, vfork); + +int +_vfork(void) +{ + return (fork()); +} diff --git a/lib/libc_r/uthread/uthread_wait.c b/lib/libc_r/uthread/uthread_wait.c new file mode 100644 index 0000000..e61138b --- /dev/null +++ b/lib/libc_r/uthread/uthread_wait.c @@ -0,0 +1,47 @@ +/* + * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. + * 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(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) 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. + * + * $FreeBSD$ + */ + +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_wait, wait); + +pid_t +_wait(int *istat) +{ + pid_t ret; + + _thread_enter_cancellation_point(); + ret = __wait(istat); + _thread_leave_cancellation_point(); + + return ret; +} diff --git a/lib/libc_r/uthread/uthread_wait4.c b/lib/libc_r/uthread/uthread_wait4.c new file mode 100644 index 0000000..6c4e068 --- /dev/null +++ b/lib/libc_r/uthread/uthread_wait4.c @@ -0,0 +1,70 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <sys/types.h> + +#include <errno.h> +#include <sys/wait.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_wait4, wait4); + +pid_t +_wait4(pid_t pid, int *istat, int options, struct rusage * rusage) +{ + struct pthread *curthread = _get_curthread(); + pid_t ret; + + _thread_kern_sig_defer(); + + /* Perform a non-blocking wait4 syscall: */ + while ((ret = __sys_wait4(pid, istat, options | WNOHANG, rusage)) == 0 && (options & WNOHANG) == 0) { + /* Reset the interrupted operation flag: */ + curthread->interrupted = 0; + + /* Schedule the next thread while this one waits: */ + _thread_kern_sched_state(PS_WAIT_WAIT, __FILE__, __LINE__); + + /* Check if this call was interrupted by a signal: */ + if (curthread->interrupted) { + errno = EINTR; + ret = -1; + break; + } + } + + _thread_kern_sig_undefer(); + + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_waitpid.c b/lib/libc_r/uthread/uthread_waitpid.c new file mode 100644 index 0000000..fcbbc9f --- /dev/null +++ b/lib/libc_r/uthread/uthread_waitpid.c @@ -0,0 +1,49 @@ +/* + * Copyright (C) 2000 Jason Evans <jasone@freebsd.org>. + * 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(s), this list of conditions and the following disclaimer as + * the first lines of this file unmodified other than the possible + * addition of one or more copyright notices. + * 2. Redistributions in binary form must reproduce the above copyright + * notice(s), this list of conditions and the following disclaimer in + * the documentation and/or other materials provided with the + * distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER(S) ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER(S) 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. + * + * $FreeBSD$ + */ + +#include <sys/types.h> +#include <sys/wait.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_waitpid, waitpid); + +pid_t +_waitpid(pid_t wpid, int *status, int options) +{ + pid_t ret; + + _thread_enter_cancellation_point(); + ret = __waitpid(wpid, status, options); + _thread_leave_cancellation_point(); + + return ret; +} diff --git a/lib/libc_r/uthread/uthread_write.c b/lib/libc_r/uthread/uthread_write.c new file mode 100644 index 0000000..e655a34 --- /dev/null +++ b/lib/libc_r/uthread/uthread_write.c @@ -0,0 +1,147 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + * + */ +#include <sys/types.h> +#include <sys/fcntl.h> +#include <sys/uio.h> +#include <errno.h> +#include <unistd.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(__write, write); + +ssize_t +_write(int fd, const void *buf, size_t nbytes) +{ + struct pthread *curthread = _get_curthread(); + int blocking; + int type; + ssize_t n; + ssize_t num = 0; + ssize_t ret; + + /* POSIX says to do just this: */ + if (nbytes == 0) + return (0); + + /* Lock the file descriptor for write: */ + if ((ret = _FD_LOCK(fd, FD_WRITE, NULL)) == 0) { + /* Get the read/write mode type: */ + type = _thread_fd_table[fd]->flags & O_ACCMODE; + + /* Check if the file is not open for write: */ + if (type != O_WRONLY && type != O_RDWR) { + /* File is not open for write: */ + errno = EBADF; + _FD_UNLOCK(fd, FD_WRITE); + return (-1); + } + + /* Check if file operations are to block */ + blocking = ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0); + + /* + * Loop while no error occurs and until the expected number + * of bytes are written if performing a blocking write: + */ + while (ret == 0) { + /* Perform a non-blocking write syscall: */ + n = __sys_write(fd, buf + num, nbytes - num); + + /* Check if one or more bytes were written: */ + if (n > 0) + /* + * Keep a count of the number of bytes + * written: + */ + num += n; + + /* + * If performing a blocking write, check if the + * write would have blocked or if some bytes + * were written but there are still more to + * write: + */ + if (blocking && ((n < 0 && (errno == EWOULDBLOCK || + errno == EAGAIN)) || (n >= 0 && num < nbytes))) { + curthread->data.fd.fd = fd; + _thread_kern_set_timeout(NULL); + + /* Reset the interrupted operation flag: */ + curthread->interrupted = 0; + + _thread_kern_sched_state(PS_FDW_WAIT, + __FILE__, __LINE__); + + /* + * Check if the operation was + * interrupted by a signal + */ + if (curthread->interrupted) { + /* Return an error: */ + ret = -1; + } + + /* + * If performing a non-blocking write or if an + * error occurred, just return whatever the write + * syscall did: + */ + } else if (!blocking || n < 0) { + /* A non-blocking call might return zero: */ + ret = n; + break; + + /* Check if the write has completed: */ + } else if (num >= nbytes) + /* Return the number of bytes written: */ + ret = num; + } + _FD_UNLOCK(fd, FD_WRITE); + } + return (ret); +} + +ssize_t +__write(int fd, const void *buf, size_t nbytes) +{ + ssize_t ret; + + _thread_enter_cancellation_point(); + ret = _write(fd, buf, nbytes); + _thread_leave_cancellation_point(); + + return ret; +} diff --git a/lib/libc_r/uthread/uthread_writev.c b/lib/libc_r/uthread/uthread_writev.c new file mode 100644 index 0000000..c084cd0 --- /dev/null +++ b/lib/libc_r/uthread/uthread_writev.c @@ -0,0 +1,204 @@ +/* + * Copyright (c) 1995-1998 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 AUTHOR 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. + * + * $FreeBSD$ + * + */ +#include <sys/types.h> +#include <sys/fcntl.h> +#include <sys/uio.h> +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <unistd.h> +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_writev, writev); + +ssize_t +_writev(int fd, const struct iovec * iov, int iovcnt) +{ + struct pthread *curthread = _get_curthread(); + int blocking; + int idx = 0; + int type; + ssize_t cnt; + ssize_t n; + ssize_t num = 0; + ssize_t ret; + struct iovec liov[20]; + struct iovec *p_iov = liov; + + /* Check if the array size exceeds to compiled in size: */ + if (iovcnt > (sizeof(liov) / sizeof(struct iovec))) { + /* Allocate memory for the local array: */ + if ((p_iov = (struct iovec *) + malloc(iovcnt * sizeof(struct iovec))) == NULL) { + /* Insufficient memory: */ + errno = ENOMEM; + return (-1); + } + } + + /* Copy the caller's array so that it can be modified locally: */ + memcpy(p_iov,iov,iovcnt * sizeof(struct iovec)); + + /* Lock the file descriptor for write: */ + if ((ret = _FD_LOCK(fd, FD_WRITE, NULL)) == 0) { + /* Get the read/write mode type: */ + type = _thread_fd_table[fd]->flags & O_ACCMODE; + + /* Check if the file is not open for write: */ + if (type != O_WRONLY && type != O_RDWR) { + /* File is not open for write: */ + errno = EBADF; + _FD_UNLOCK(fd, FD_WRITE); + return (-1); + } + + /* Check if file operations are to block */ + blocking = ((_thread_fd_table[fd]->flags & O_NONBLOCK) == 0); + + /* + * Loop while no error occurs and until the expected number + * of bytes are written if performing a blocking write: + */ + while (ret == 0) { + /* Perform a non-blocking write syscall: */ + n = __sys_writev(fd, &p_iov[idx], iovcnt - idx); + + /* Check if one or more bytes were written: */ + if (n > 0) { + /* + * Keep a count of the number of bytes + * written: + */ + num += n; + + /* + * Enter a loop to check if a short write + * occurred and move the index to the + * array entry where the short write + * ended: + */ + cnt = n; + while (cnt > 0 && idx < iovcnt) { + /* + * If the residual count exceeds + * the size of this vector, then + * it was completely written: + */ + if (cnt >= p_iov[idx].iov_len) + /* + * Decrement the residual + * count and increment the + * index to the next array + * entry: + */ + cnt -= p_iov[idx++].iov_len; + else { + /* + * This entry was only + * partially written, so + * adjust it's length + * and base pointer ready + * for the next write: + */ + p_iov[idx].iov_len -= cnt; + p_iov[idx].iov_base += cnt; + cnt = 0; + } + } + } else if (n == 0) { + /* + * Avoid an infinite loop if the last iov_len is + * 0. + */ + while (idx < iovcnt && p_iov[idx].iov_len == 0) + idx++; + + if (idx == iovcnt) { + ret = num; + break; + } + } + + /* + * If performing a blocking write, check if the + * write would have blocked or if some bytes + * were written but there are still more to + * write: + */ + if (blocking && ((n < 0 && (errno == EWOULDBLOCK || + errno == EAGAIN)) || (n >= 0 && idx < iovcnt))) { + curthread->data.fd.fd = fd; + _thread_kern_set_timeout(NULL); + + /* Reset the interrupted operation flag: */ + curthread->interrupted = 0; + + _thread_kern_sched_state(PS_FDW_WAIT, + __FILE__, __LINE__); + + /* + * Check if the operation was + * interrupted by a signal + */ + if (curthread->interrupted) { + /* Return an error: */ + ret = -1; + } + + /* + * If performing a non-blocking write or if an + * error occurred, just return whatever the write + * syscall did: + */ + } else if (!blocking || n < 0) { + /* A non-blocking call might return zero: */ + ret = n; + break; + + /* Check if the write has completed: */ + } else if (idx == iovcnt) + /* Return the number of bytes written: */ + ret = num; + } + _FD_UNLOCK(fd, FD_RDWR); + } + + /* If memory was allocated for the array, free it: */ + if (p_iov != liov) + free(p_iov); + + return (ret); +} diff --git a/lib/libc_r/uthread/uthread_yield.c b/lib/libc_r/uthread/uthread_yield.c new file mode 100644 index 0000000..ec89255 --- /dev/null +++ b/lib/libc_r/uthread/uthread_yield.c @@ -0,0 +1,66 @@ +/* + * 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 AUTHOR 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. + * + * $FreeBSD$ + */ +#include <pthread.h> +#include "pthread_private.h" + +__weak_reference(_sched_yield, sched_yield); +__weak_reference(_pthread_yield, pthread_yield); + +int +_sched_yield(void) +{ + struct pthread *curthread = _get_curthread(); + + /* Reset the accumulated time slice value for the current thread: */ + curthread->slice_usec = -1; + + /* Schedule the next thread: */ + _thread_kern_sched(NULL); + + /* Always return no error. */ + return(0); +} + +/* Draft 4 yield */ +void +_pthread_yield(void) +{ + struct pthread *curthread = _get_curthread(); + + /* Reset the accumulated time slice value for the current thread: */ + curthread->slice_usec = -1; + + /* Schedule the next thread: */ + _thread_kern_sched(NULL); +} |