summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarco S Hyman <marc@cvs.openbsd.org>2003-02-04 22:14:28 +0000
committerMarco S Hyman <marc@cvs.openbsd.org>2003-02-04 22:14:28 +0000
commit5f11a81a04b25b7f64a86ad418f79529df7cae52 (patch)
tree5f656a0decb261f61791bf87d1919c2f25de511a
parent0691abffebb064ad7318896c4ee8b0a26b049654 (diff)
Part 1 of thread fd handling fixes. In the new scheme fd_table_entries
for dup-ed fds are shared to ensure proper flag handling. A refcnt was added to control when entries should be freed. Specific changes: close: don't free entry unless refcnt is zero dup: rewrite to use new function _thread_fd_table_dup dup2: rewrite to use new function _thread_fd_table_dup fcntl: use _thread_fd_table_dup uthread_fd: initialize thread fd table, searching for dup-ed fds. Add function to share _thread_fd_table entries when an fd is dup-ed. uthread_init: make it readable. Call fd init functions. All current regression tests plus the mysql torture test pass. The new stdfiles regression test fails (I/O redirection problem). Part 2 is intended to fix that problem
-rw-r--r--lib/libpthread/uthread/pthread_private.h29
-rw-r--r--lib/libpthread/uthread/uthread_close.c5
-rw-r--r--lib/libpthread/uthread/uthread_dup.c64
-rw-r--r--lib/libpthread/uthread/uthread_dup2.c85
-rw-r--r--lib/libpthread/uthread/uthread_fcntl.c10
-rw-r--r--lib/libpthread/uthread/uthread_fd.c148
-rw-r--r--lib/libpthread/uthread/uthread_init.c352
7 files changed, 325 insertions, 368 deletions
diff --git a/lib/libpthread/uthread/pthread_private.h b/lib/libpthread/uthread/pthread_private.h
index 639ab7d916f..9d5b9bf2747 100644
--- a/lib/libpthread/uthread/pthread_private.h
+++ b/lib/libpthread/uthread/pthread_private.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pthread_private.h,v 1.43 2003/01/31 04:46:17 marc Exp $ */
+/* $OpenBSD: pthread_private.h,v 1.44 2003/02/04 22:14:27 marc Exp $ */
/*
* Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>.
* All rights reserved.
@@ -500,17 +500,18 @@ struct fd_table_entry {
* state of the lock on the file descriptor.
*/
spinlock_t lock;
- _thread_list_t r_queue; /* Read queue. */
- _thread_list_t w_queue; /* Write queue. */
- struct pthread *r_owner; /* Ptr to thread owning read lock. */
- struct pthread *w_owner; /* Ptr to thread owning write lock. */
- const char *r_fname; /* Ptr to read lock source file name */
- int r_lineno; /* Read lock source line number. */
- const 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. */
+ _thread_list_t r_queue; /* Read queue. */
+ _thread_list_t w_queue; /* Write queue. */
+ struct pthread *r_owner; /* thread owning read lock. */
+ struct pthread *w_owner; /* thread owning write lock. */
+ const char *r_fname; /* read lock source file name */
+ int r_lineno; /* Read lock source line no. */
+ const char *w_fname; /* write lock src file name */
+ int w_lineno; /* Write lock src line no. */
+ int r_lockcount; /* Count for FILE read locks. */
+ int w_lockcount; /* Count for FILE write locks.*/
+ int flags; /* Flags used in open. */
+ int refcnt; /* how many fds use this entry*/
};
struct pthread_poll_data {
@@ -1108,7 +1109,9 @@ void _thread_sig_init(void);
void _thread_start(void);
void _thread_start_sig_handler(void);
void _thread_seterrno(pthread_t,int);
-int _thread_fd_table_init(int fd);
+void _thread_fd_init(void);
+int _thread_fd_table_init(int);
+int _thread_fd_table_dup(int, int);
void _thread_fd_unlock_owned(pthread_t);
void _thread_fd_unlock_thread(struct pthread *, int, int, const char *, int);
pthread_addr_t _thread_gc(pthread_addr_t);
diff --git a/lib/libpthread/uthread/uthread_close.c b/lib/libpthread/uthread/uthread_close.c
index 87b86611469..7597338269d 100644
--- a/lib/libpthread/uthread/uthread_close.c
+++ b/lib/libpthread/uthread/uthread_close.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uthread_close.c,v 1.8 2000/10/04 05:52:34 d Exp $ */
+/* $OpenBSD: uthread_close.c,v 1.9 2003/02/04 22:14:27 marc Exp $ */
/*
* Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
* All rights reserved.
@@ -102,7 +102,8 @@ close(int fd)
/* XXX: Defer real close to avoid race condition */
entry = _thread_fd_table[fd];
_thread_fd_table[fd] = NULL;
- free(entry);
+ if (--entry->refcnt == 0)
+ free(entry);
/* Close the file descriptor: */
ret = _thread_sys_close(fd);
diff --git a/lib/libpthread/uthread/uthread_dup.c b/lib/libpthread/uthread/uthread_dup.c
index 8aba9a1dba6..ad1adc3081d 100644
--- a/lib/libpthread/uthread/uthread_dup.c
+++ b/lib/libpthread/uthread/uthread_dup.c
@@ -1,37 +1,6 @@
-/* $OpenBSD: uthread_dup.c,v 1.3 1999/11/25 07:01:33 d Exp $ */
-/*
- * 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: uthread_dup.c,v 1.5 1999/08/28 00:03:29 peter Exp $
- */
+/* $OpenBSD: uthread_dup.c,v 1.4 2003/02/04 22:14:27 marc Exp $ */
+/* PUBLIC DOMAIN <marc@snafu.org> */
+
#include <unistd.h>
#ifdef _THREAD_SAFE
#include <pthread.h>
@@ -42,30 +11,13 @@ dup(int fd)
{
int ret;
- /* Lock the file descriptor: */
- if ((ret = _FD_LOCK(fd, FD_RDWR, NULL)) == 0) {
- /* Perform the 'dup' syscall: */
- if ((ret = _thread_sys_dup(fd)) < 0) {
- }
- /* Initialise the file descriptor table entry: */
- else if (_thread_fd_table_init(ret) != 0) {
- /* Quietly close the file: */
- _thread_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: */
+ ret = _FD_LOCK(fd, FD_RDWR, NULL);
+ if (ret == 0) {
+ ret = _thread_sys_dup(fd);
+ if (ret != -1)
+ ret = _thread_fd_table_dup(fd, ret);
_FD_UNLOCK(fd, FD_RDWR);
}
- /* Return the completion status: */
return (ret);
}
#endif
diff --git a/lib/libpthread/uthread/uthread_dup2.c b/lib/libpthread/uthread/uthread_dup2.c
index 5809c4c66b7..61b172b3fc3 100644
--- a/lib/libpthread/uthread/uthread_dup2.c
+++ b/lib/libpthread/uthread/uthread_dup2.c
@@ -1,37 +1,6 @@
-/* $OpenBSD: uthread_dup2.c,v 1.5 2002/02/19 01:10:24 fgsch Exp $ */
-/*
- * 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: uthread_dup2.c,v 1.6 1999/08/28 00:03:29 peter Exp $
- */
+/* $OpenBSD: uthread_dup2.c,v 1.6 2003/02/04 22:14:27 marc Exp $ */
+/* PUBLIC DOMAIN <marc@snafu.org> */
+
#include <errno.h>
#include <unistd.h>
#ifdef _THREAD_SAFE
@@ -41,48 +10,22 @@
int
dup2(int fd, int newfd)
{
- int ret;
- int newfd_opened;
+ int ret;
- /* 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: */
+ if (newfd >= 0 && newfd < _thread_dtablesize &&
+ newfd != _thread_kern_pipe[0] && newfd != _thread_kern_pipe[1]) {
+ ret = _FD_LOCK(fd, FD_RDWR, NULL);
+ if (ret == 0) {
+ ret = _thread_sys_dup2(fd, newfd);
+ if (ret != -1)
+ ret = _thread_fd_table_dup(fd, newfd);
+ _FD_UNLOCK(fd, FD_RDWR);
+ }
+ } else {
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 = _thread_sys_dup2(fd, newfd)) < 0) {
- }
- /* Initialise the file descriptor table entry: */
- else if (_thread_fd_table_init(ret) != 0) {
- /* Quietly close the file: */
- _thread_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);
}
#endif
diff --git a/lib/libpthread/uthread/uthread_fcntl.c b/lib/libpthread/uthread/uthread_fcntl.c
index 7070a564838..8955618efcd 100644
--- a/lib/libpthread/uthread/uthread_fcntl.c
+++ b/lib/libpthread/uthread/uthread_fcntl.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uthread_fcntl.c,v 1.6 1999/11/25 07:01:34 d Exp $ */
+/* $OpenBSD: uthread_fcntl.c,v 1.7 2003/02/04 22:14:27 marc Exp $ */
/*
* Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
* All rights reserved.
@@ -70,18 +70,12 @@ fcntl(int fd, int cmd,...)
if ((ret = _thread_sys_fcntl(fd, cmd, oldfd)) < 0) {
}
/* Initialise the file descriptor table entry: */
- else if (_thread_fd_table_init(ret) != 0) {
+ else if (_thread_fd_table_dup(fd, ret) != 0) {
/* Quietly close the file: */
_thread_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:
diff --git a/lib/libpthread/uthread/uthread_fd.c b/lib/libpthread/uthread/uthread_fd.c
index 5a998fbba7e..f583fe04067 100644
--- a/lib/libpthread/uthread/uthread_fd.c
+++ b/lib/libpthread/uthread/uthread_fd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uthread_fd.c,v 1.16 2003/01/19 21:22:31 marc Exp $ */
+/* $OpenBSD: uthread_fd.c,v 1.17 2003/02/04 22:14:27 marc Exp $ */
/*
* Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
* All rights reserved.
@@ -45,6 +45,97 @@
static spinlock_t fd_table_lock = _SPINLOCK_INITIALIZER;
/*
+ * Build a new fd entry and return it.
+ */
+static struct fd_table_entry *
+_thread_fd_entry(void)
+{
+ struct fd_table_entry *entry;
+
+ entry = (struct fd_table_entry *) malloc(sizeof(struct fd_table_entry));
+ if (entry != NULL) {
+ memset(entry, 0, sizeof *entry);
+ _SPINLOCK_INIT(&entry->lock);
+ TAILQ_INIT(&entry->r_queue);
+ TAILQ_INIT(&entry->w_queue);
+ }
+ return entry;
+}
+
+/*
+ * Initialize the thread fd table for dup-ed fds, typically the stdio
+ * fds.
+ */
+
+void
+_thread_fd_init(void)
+{
+ int saved_errno;
+ int fd;
+ int fd2;
+ int flag;
+ int *flags;
+ struct fd_table_entry *entry;
+
+ saved_errno = errno;
+ flags = calloc(_thread_dtablesize, sizeof *flags);
+ if (flags == NULL)
+ PANIC("Cannot allocate memory for flags table");
+
+
+ /* read the current file flags */
+ for (fd = 0; fd < _thread_dtablesize; fd += 1)
+ flags[fd] = _thread_sys_fcntl(fd, F_GETFL, 0);
+
+ /*
+ * Now toggle the non-block flags and see what other fd's
+ * change. Those are the dup-ed fd's. Dup-ed fd's are
+ * added to the table, all others are NOT added to the
+ * table. They MUST NOT be added as the fds may belong
+ * to dlopen and dlclose doesn't go through the thread code
+ * so the entries would never be cleaned.
+ */
+
+ _SPINLOCK(&fd_table_lock);
+ for (fd = 0; fd < _thread_dtablesize; fd += 1) {
+ if (flags[fd] == -1)
+ continue;
+ entry = _thread_fd_entry();
+ if (entry != NULL) {
+ entry->flags = flags[fd];
+ _thread_sys_fcntl(fd, F_SETFL,
+ entry->flags ^ O_NONBLOCK);
+ for (fd2 = fd + 1; fd2 < _thread_dtablesize; fd2 += 1) {
+ if (flags[fd2] == -1)
+ continue;
+ flag = _thread_sys_fcntl(fd2, F_GETFL, 0);
+ if (flag != flags[fd2]) {
+ entry->refcnt += 1;
+ _thread_fd_table[fd2] = entry;
+ flags[fd2] = -1;
+ }
+ }
+ if (entry->refcnt) {
+ entry->refcnt += 1;
+ _thread_fd_table[fd] = entry;
+ } else
+ free(entry);
+ }
+ }
+ _SPINUNLOCK(&fd_table_lock);
+
+ /* lastly, set all files to non-blocking, ignoring errors for
+ those files/devices that don't support such a mode. */
+ for (fd = 0; fd < _thread_dtablesize; fd += 1)
+ if (flags[fd] != -1)
+ _thread_sys_fcntl(fd, F_SETFL,
+ flags[fd] | O_NONBLOCK);
+
+ free(flags);
+ errno = saved_errno;
+}
+
+/*
* Initialize the fd_table entry for the given fd.
*
* This function *must* return -1 and set the thread specific errno
@@ -68,28 +159,11 @@ _thread_fd_table_init(int fd)
ret = -1;
} else if (_thread_fd_table[fd] == NULL) {
/* First time for this fd, build an entry */
- entry = (struct fd_table_entry *)
- malloc(sizeof(struct fd_table_entry));
+ entry = _thread_fd_entry();
if (entry == NULL) {
errno = ENOMEM;
ret = -1;
} else {
- /* Initialise the file locks: */
- _SPINLOCK_INIT(&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: */
entry->flags = _thread_sys_fcntl(fd, F_GETFL, 0);
if (entry->flags == -1)
/* use the errno fcntl returned */
@@ -118,8 +192,8 @@ _thread_fd_table_init(int fd)
*/
if (_thread_fd_table[fd] == NULL) {
/* This thread wins: */
+ entry->refcnt += 1;
_thread_fd_table[fd] = entry;
- entry = NULL;
}
/* Unlock the file descriptor table: */
@@ -131,7 +205,7 @@ _thread_fd_table_init(int fd)
* the file or if another thread initialized the
* table entry throw this entry away.
*/
- if (entry != NULL)
+ if (entry->refcnt == 0)
free(entry);
}
}
@@ -141,6 +215,38 @@ _thread_fd_table_init(int fd)
}
/*
+ * Dup from_fd -> to_fd. from_fd is assumed to be locked (which
+ * guarantees that _thread_fd_table[from_fd] exists).
+ */
+int
+_thread_fd_table_dup(int from_fd, int to_fd)
+{
+ struct fd_table_entry *entry;
+ int ret;
+
+ /* release any existing to_fd table entry */
+ entry = _thread_fd_table[to_fd];
+ if (entry != NULL) {
+ ret = _FD_LOCK(to_fd, FD_RDWR, NULL);
+ if (ret != -1) {
+ if (--entry->refcnt == 0)
+ free(entry);
+ }
+ } else
+ ret = 0;
+
+ /* to_fd is a copy of from_fd */
+ if (ret != -1) {
+ _SPINLOCK(&fd_table_lock);
+ _thread_fd_table[to_fd] = _thread_fd_table[from_fd];
+ _thread_fd_table[to_fd]->refcnt += 1;
+ _SPINUNLOCK(&fd_table_lock);
+ }
+
+ return (ret);
+}
+
+/*
* Unlock the fd table entry for a given thread, fd, and lock type.
*/
void
diff --git a/lib/libpthread/uthread/uthread_init.c b/lib/libpthread/uthread/uthread_init.c
index db517e6d97f..1be9ce7ca3a 100644
--- a/lib/libpthread/uthread/uthread_init.c
+++ b/lib/libpthread/uthread/uthread_init.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: uthread_init.c,v 1.27 2003/01/31 04:46:17 marc Exp $ */
+/* $OpenBSD: uthread_init.c,v 1.28 2003/02/04 22:14:27 marc Exp $ */
/*
* Copyright (c) 1995-1998 John Birrell <jb@cimlogic.com.au>
* All rights reserved.
@@ -148,6 +148,7 @@ _thread_init(void)
{
int fd;
int flags;
+ int res;
int i;
size_t len;
int mib[2];
@@ -191,219 +192,176 @@ _thread_init(void)
* Create a pipe that is written to by the signal handler to prevent
* signals being missed in calls to _select:
*/
- if (_thread_sys_pipe(_thread_kern_pipe) != 0) {
- /* Cannot create pipe, so abort: */
+ if (_thread_sys_pipe(_thread_kern_pipe) != 0)
PANIC("Cannot create kernel pipe");
- }
- /* Get the flags for the read pipe: */
- else if ((flags = _thread_sys_fcntl(_thread_kern_pipe[0], F_GETFL, NULL)) == -1) {
- /* Abort this application: */
+
+ flags = _thread_sys_fcntl(_thread_kern_pipe[0], F_GETFL, NULL);
+ if (flags == -1)
PANIC("Cannot get kernel read pipe flags");
- }
- /* Make the read pipe non-blocking: */
- else if (_thread_sys_fcntl(_thread_kern_pipe[0], F_SETFL, flags | O_NONBLOCK) == -1) {
- /* Abort this application: */
+
+ res = _thread_sys_fcntl(_thread_kern_pipe[0], F_SETFL,
+ flags | O_NONBLOCK);
+ if (res == -1)
PANIC("Cannot make kernel read pipe non-blocking");
- }
- /* Get the flags for the write pipe: */
- else if ((flags = _thread_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 (_thread_sys_fcntl(_thread_kern_pipe[1], F_SETFL, flags | O_NONBLOCK) == -1) {
- /* Abort this application: */
+
+ flags = _thread_sys_fcntl(_thread_kern_pipe[1], F_GETFL, NULL);
+ if (flags == -1)
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: */
+
+ res = _thread_sys_fcntl(_thread_kern_pipe[1], F_SETFL,
+ flags | O_NONBLOCK);
+ if (res == -1)
+ PANIC("Cannot make kernel write pipe non-blocking");
+
+ res = _pq_alloc(&_readyq, PTHREAD_MIN_PRIORITY, PTHREAD_LAST_PRIORITY);
+ if (res != 0)
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:
- */
+
+ _thread_initial = (pthread_t) malloc(sizeof(struct pthread));
+ if (_thread_initial == NULL)
PANIC("Cannot allocate memory for initial thread");
- } 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;
+ /* 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 thread stack cache: */
- SLIST_INIT(&_stackq);
+ /* Initialize the waiting and work queues: */
+ TAILQ_INIT(&_waitingq);
+ TAILQ_INIT(&_workq);
- /*
- * 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;
-
- /* 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;
-
- /* Give it a useful name */
- pthread_set_name_np(_thread_initial, (char *)"main");
-
- /* 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->slice_usec = -1;
- _thread_initial->sig_saved = 0;
- _thread_initial->yield_on_sig_undefer = 0;
- _thread_initial->specific_data = NULL;
- _thread_initial->cleanup = NULL;
- _thread_initial->flags = 0;
- _thread_initial->error = 0;
- _SPINLOCK_INIT(&_thread_initial->lock);
- 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 (*) (int)) _thread_sig_handler;
- act.sa_flags = SA_SIGINFO;
-
- /* Clear pending signals for the process: */
- sigemptyset(&_process_sigpending);
-
- /* Initialize signal handling: */
- _thread_sig_init();
-
- /* 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 (_thread_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;
- }
+ /* Initialize the scheduling switch hook routine: */
+ _sched_switch_hook = NULL;
- /*
- * 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 (_thread_sys_sigaction(_SCHED_SIGNAL, &act, NULL) != 0 ||
- _thread_sys_sigaction(SIGINFO, &act, NULL) != 0 ||
- _thread_sys_sigaction(SIGCHLD, &act, NULL) != 0) {
- /*
- * Abort this process if signal initialization fails:
- */
- PANIC("Cannot initialize 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: */
- _thread_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");
- }
- }
+ /* Initialize the thread stack cache: */
+ SLIST_INIT(&_stackq);
+
+ /*
+ * 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;
+
+ /* 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;
+
+ /* Give it a useful name */
+ pthread_set_name_np(_thread_initial, (char *)"main");
+
+ /* 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->slice_usec = -1;
+ _thread_initial->sig_saved = 0;
+ _thread_initial->yield_on_sig_undefer = 0;
+ _thread_initial->specific_data = NULL;
+ _thread_initial->cleanup = NULL;
+ _thread_initial->flags = 0;
+ _thread_initial->error = 0;
+ _SPINLOCK_INIT(&_thread_initial->lock);
+ 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 (*) (int)) _thread_sig_handler;
+ act.sa_flags = SA_SIGINFO;
+
+ /* Clear pending signals for the process: */
+ sigemptyset(&_process_sigpending);
+
+ /* Initialize signal handling: */
+ _thread_sig_init();
+
+ /* 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)
+ continue;
+
+ /* Get the signal handler details: */
+ if (_thread_sys_sigaction(i, NULL, &_thread_sigact[i - 1]) != 0)
+ 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 (_thread_sys_sigaction(_SCHED_SIGNAL, &act, NULL) != 0 ||
+ _thread_sys_sigaction(SIGINFO, &act, NULL) != 0 ||
+ _thread_sys_sigaction(SIGCHLD, &act, NULL) != 0)
+ PANIC("Cannot initialize 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: */
+ _thread_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)
+ PANIC("Cannot get dtablesize");
+
+ /* Allocate memory for the file descriptor table: */
+ _thread_fd_table = calloc(_thread_dtablesize,
+ sizeof(struct fd_table_entry *));
+ if (_thread_fd_table == NULL) {
+ _thread_dtablesize = 0;
+ PANIC("Cannot allocate memory for file descriptor table");
+ }
+
+ /* Allocate memory for the pollfd table: */
+ _thread_pfd_table = calloc(_thread_dtablesize, sizeof(struct pollfd));
+ if (_thread_pfd_table == NULL)
+ PANIC("Cannot allocate memory for pollfd table");
+
+ /* initialize the fd table */
+ _thread_fd_init();
+
/* 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");
-
_thread_autoinit_dummy_decl = 0;
}
#endif