thr_init.c revision 25795
1/*
2 * Copyright (c) 1995 John Birrell <jb@cimlogic.com.au>.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *	This product includes software developed by John Birrell.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 */
33
34/* Allocate space for global thread variables here: */
35#define GLOBAL_PTHREAD_PRIVATE
36
37#include <errno.h>
38#include <stdlib.h>
39#include <string.h>
40#include <fcntl.h>
41#include <unistd.h>
42#include <sys/time.h>
43#ifdef _THREAD_SAFE
44#include <machine/reg.h>
45#include <pthread.h>
46#include "pthread_private.h"
47extern int _thread_autoinit_dummy_decl;
48
49/*
50 * Threaded process initialization
51 */
52void
53_thread_init(void)
54{
55	int             flags;
56	int             i;
57	struct sigaction act;
58
59	/* Ensure that the auto-initialization routine is linked in: */
60	_thread_autoinit_dummy_decl = 1;
61
62	/* Check if this function has already been called: */
63	if (_thread_initial)
64		/* Only initialise the threaded application once. */
65		return;
66
67	/* Get the standard I/O flags before messing with them : */
68	for (i = 0; i < 3; i++)
69		if ((_pthread_stdio_flags[i] =
70		    _thread_sys_fcntl(i,F_GETFL, NULL)) == -1)
71			PANIC("Cannot get stdio flags");
72
73	/*
74	 * Create a pipe that is written to by the signal handler to prevent
75	 * signals being missed in calls to _thread_sys_select:
76	 */
77	if (_thread_sys_pipe(_thread_kern_pipe) != 0) {
78		/* Cannot create pipe, so abort: */
79		PANIC("Cannot create kernel pipe");
80	}
81	/* Get the flags for the read pipe: */
82	else if ((flags = _thread_sys_fcntl(_thread_kern_pipe[0], F_GETFL, NULL)) == -1) {
83		/* Abort this application: */
84		PANIC("Cannot get kernel read pipe flags");
85	}
86	/* Make the read pipe non-blocking: */
87	else if (_thread_sys_fcntl(_thread_kern_pipe[0], F_SETFL, flags | O_NONBLOCK) == -1) {
88		/* Abort this application: */
89		PANIC("Cannot make kernel read pipe non-blocking");
90	}
91	/* Get the flags for the write pipe: */
92	else if ((flags = _thread_sys_fcntl(_thread_kern_pipe[1], F_GETFL, NULL)) == -1) {
93		/* Abort this application: */
94		PANIC("Cannot get kernel write pipe flags");
95	}
96	/* Make the write pipe non-blocking: */
97	else if (_thread_sys_fcntl(_thread_kern_pipe[1], F_SETFL, flags | O_NONBLOCK) == -1) {
98		/* Abort this application: */
99		PANIC("Cannot get kernel write pipe flags");
100	}
101	/* Allocate memory for the thread structure of the initial thread: */
102	else if ((_thread_initial = (pthread_t) malloc(sizeof(struct pthread))) == NULL) {
103		/*
104		 * Insufficient memory to initialise this application, so
105		 * abort:
106		 */
107		PANIC("Cannot allocate memory for initial thread");
108	} else {
109		/* Zero the global kernel thread structure: */
110		memset(&_thread_kern_thread, 0, sizeof(struct pthread));
111		memset(_thread_initial, 0, sizeof(struct pthread));
112
113		/* Default the priority of the initial thread: */
114		_thread_initial->pthread_priority = PTHREAD_DEFAULT_PRIORITY;
115
116		/* Initialise the state of the initial thread: */
117		_thread_initial->state = PS_RUNNING;
118
119		/* Initialise the queue: */
120		_thread_queue_init(&(_thread_initial->join_queue));
121
122		/* Initialise the rest of the fields: */
123		_thread_initial->parent_thread = NULL;
124		_thread_initial->specific_data = NULL;
125		_thread_initial->cleanup = NULL;
126		_thread_initial->queue = NULL;
127		_thread_initial->qnxt = NULL;
128		_thread_initial->nxt = NULL;
129		_thread_initial->flags = 0;
130		_thread_initial->error = 0;
131		_thread_link_list = _thread_initial;
132		_thread_run = _thread_initial;
133
134		/* Enter a loop to get the existing signal status: */
135		for (i = 1; i < NSIG; i++) {
136			/* Check for signals which cannot be trapped: */
137			if (i == SIGKILL || i == SIGSTOP) {
138			}
139			/* Get the signal handler details: */
140			else if (_thread_sys_sigaction(i, NULL, &act) != 0) {
141				/*
142				 * Abort this process if signal
143				 * initialisation fails:
144				 */
145				PANIC("Cannot read signal handler info");
146			}
147			/* Set the signal handler for the initial thread: */
148			else if (sigaction(i, &act, NULL) != 0) {
149				/*
150				 * Abort this process if signal
151				 * initialisation fails:
152				 */
153				PANIC("Cannot initialise signal handler for initial thread");
154			}
155		}
156
157		/* Initialise the global signal action structure: */
158		sigfillset(&act.sa_mask);
159		act.sa_handler = (void (*) ()) _thread_sig_handler;
160		act.sa_flags = SA_RESTART;
161
162		/* Enter a loop to initialise the rest of the signals: */
163		for (i = 1; i < NSIG; i++) {
164			/* Check for signals which cannot be trapped: */
165			if (i == SIGKILL || i == SIGSTOP) {
166			}
167			/* Initialise the signal for default handling: */
168			else if (_thread_sys_sigaction(i, &act, NULL) != 0) {
169				/*
170				 * Abort this process if signal
171				 * initialisation fails:
172				 */
173				PANIC("Cannot initialise signal handler");
174			}
175		}
176
177		/* Get the table size: */
178		if ((_thread_dtablesize = getdtablesize()) < 0) {
179			/*
180			 * Cannot get the system defined table size, so abort
181			 * this process.
182			 */
183			PANIC("Cannot get dtablesize");
184		}
185		/* Allocate memory for the file descriptor table: */
186		if ((_thread_fd_table = (struct fd_table_entry **) malloc(sizeof(struct fd_table_entry *) * _thread_dtablesize)) == NULL) {
187			/*
188			 * Cannot allocate memory for the file descriptor
189			 * table, so abort this process.
190			 */
191			PANIC("Cannot allocate memory for file descriptor table");
192		} else {
193			/*
194			 * Enter a loop to initialise the file descriptor
195			 * table:
196			 */
197			for (i = 0; i < _thread_dtablesize; i++) {
198				/* Initialise the file descriptor table: */
199				_thread_fd_table[i] = NULL;
200			}
201		}
202	}
203	return;
204}
205
206/*
207 * Special start up code for NetBSD/Alpha
208 */
209#if	defined(__NetBSD__) && defined(__alpha__)
210int
211main(int argc, char *argv[], char *env);
212
213int
214_thread_main(int argc, char *argv[], char *env)
215{
216	_thread_init();
217	return (main(argc, argv, env));
218}
219#endif
220#else
221/*
222 * A stub for non-threaded programs.
223 */
224void
225_thread_init(void)
226{
227}
228#endif
229