diff options
author | Marco S Hyman <marc@cvs.openbsd.org> | 2003-02-04 22:14:28 +0000 |
---|---|---|
committer | Marco S Hyman <marc@cvs.openbsd.org> | 2003-02-04 22:14:28 +0000 |
commit | 5f11a81a04b25b7f64a86ad418f79529df7cae52 (patch) | |
tree | 5f656a0decb261f61791bf87d1919c2f25de511a | |
parent | 0691abffebb064ad7318896c4ee8b0a26b049654 (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.h | 29 | ||||
-rw-r--r-- | lib/libpthread/uthread/uthread_close.c | 5 | ||||
-rw-r--r-- | lib/libpthread/uthread/uthread_dup.c | 64 | ||||
-rw-r--r-- | lib/libpthread/uthread/uthread_dup2.c | 85 | ||||
-rw-r--r-- | lib/libpthread/uthread/uthread_fcntl.c | 10 | ||||
-rw-r--r-- | lib/libpthread/uthread/uthread_fd.c | 148 | ||||
-rw-r--r-- | lib/libpthread/uthread/uthread_init.c | 352 |
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 |