]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libpthread/thread/thr_init.c
Modify previous changes to conform better to libc_r's coding style.
[FreeBSD/FreeBSD.git] / lib / libpthread / thread / thr_init.c
1 /*
2  * Copyright (c) 1995-1998 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 AUTHOR 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  * $Id: uthread_init.c,v 1.14 1999/07/06 00:25:38 jasone Exp $
33  */
34
35 /* Allocate space for global thread variables here: */
36 #define GLOBAL_PTHREAD_PRIVATE
37
38 #include <errno.h>
39 #include <stdlib.h>
40 #include <string.h>
41 #include <fcntl.h>
42 #include <paths.h>
43 #include <poll.h>
44 #include <unistd.h>
45 #include <sys/sysctl.h>
46 #include <sys/time.h>
47 #include <sys/ttycom.h>
48 #include <sys/types.h>
49 #include <sys/mman.h>
50 #ifdef _THREAD_SAFE
51 #include <machine/reg.h>
52 #include <pthread.h>
53 #include "pthread_private.h"
54
55 #ifdef GCC_2_8_MADE_THREAD_AWARE
56 typedef void *** (*dynamic_handler_allocator)();
57 extern void __set_dynamic_handler_allocator(dynamic_handler_allocator);
58
59 static pthread_key_t except_head_key;
60
61 typedef struct {
62         void **__dynamic_handler_chain;
63         void *top_elt[2];
64 } except_struct;
65
66 static void ***dynamic_allocator_handler_fn()
67 {
68         except_struct *dh = (except_struct *)pthread_getspecific(except_head_key);
69
70         if(dh == NULL) {
71                 dh = (except_struct *)malloc( sizeof(except_struct) );
72                 memset(dh, '\0', sizeof(except_struct));
73                 dh->__dynamic_handler_chain= dh->top_elt;
74                 pthread_setspecific(except_head_key, (void *)dh);
75         }
76         return &dh->__dynamic_handler_chain;
77 }
78 #endif /* GCC_2_8_MADE_THREAD_AWARE */
79
80 /*
81  * Threaded process initialization
82  */
83 void
84 _thread_init(void)
85 {
86         int             fd;
87         int             flags;
88         int             i;
89         size_t          len;
90         int             mib[2];
91         struct clockinfo clockinfo;
92         struct sigaction act;
93
94         /* Check if this function has already been called: */
95         if (_thread_initial)
96                 /* Only initialise the threaded application once. */
97                 return;
98
99         /*
100          * Check for the special case of this process running as
101          * or in place of init as pid = 1:
102          */
103         if (getpid() == 1) {
104                 /*
105                  * Setup a new session for this process which is
106                  * assumed to be running as root.
107                  */
108                 if (setsid() == -1)
109                         PANIC("Can't set session ID");
110                 if (revoke(_PATH_CONSOLE) != 0)
111                         PANIC("Can't revoke console");
112                 if ((fd = _thread_sys_open(_PATH_CONSOLE, O_RDWR)) < 0)
113                         PANIC("Can't open console");
114                 if (setlogin("root") == -1)
115                         PANIC("Can't set login to root");
116                 if (_thread_sys_ioctl(fd,TIOCSCTTY, (char *) NULL) == -1)
117                         PANIC("Can't set controlling terminal");
118                 if (_thread_sys_dup2(fd,0) == -1 ||
119                     _thread_sys_dup2(fd,1) == -1 ||
120                     _thread_sys_dup2(fd,2) == -1)
121                         PANIC("Can't dup2");
122         }
123
124         /* Get the standard I/O flags before messing with them : */
125         for (i = 0; i < 3; i++)
126                 if ((_pthread_stdio_flags[i] =
127                      _thread_sys_fcntl(i,F_GETFL, NULL)) == -1)
128                         PANIC("Cannot get stdio flags");
129
130         /*
131          * Create a pipe that is written to by the signal handler to prevent
132          * signals being missed in calls to _select: 
133          */
134         if (_thread_sys_pipe(_thread_kern_pipe) != 0) {
135                 /* Cannot create pipe, so abort: */
136                 PANIC("Cannot create kernel pipe");
137         }
138         /* Get the flags for the read pipe: */
139         else if ((flags = _thread_sys_fcntl(_thread_kern_pipe[0], F_GETFL, NULL)) == -1) {
140                 /* Abort this application: */
141                 PANIC("Cannot get kernel read pipe flags");
142         }
143         /* Make the read pipe non-blocking: */
144         else if (_thread_sys_fcntl(_thread_kern_pipe[0], F_SETFL, flags | O_NONBLOCK) == -1) {
145                 /* Abort this application: */
146                 PANIC("Cannot make kernel read pipe non-blocking");
147         }
148         /* Get the flags for the write pipe: */
149         else if ((flags = _thread_sys_fcntl(_thread_kern_pipe[1], F_GETFL, NULL)) == -1) {
150                 /* Abort this application: */
151                 PANIC("Cannot get kernel write pipe flags");
152         }
153         /* Make the write pipe non-blocking: */
154         else if (_thread_sys_fcntl(_thread_kern_pipe[1], F_SETFL, flags | O_NONBLOCK) == -1) {
155                 /* Abort this application: */
156                 PANIC("Cannot get kernel write pipe flags");
157         }
158         /* Allocate and initialize the ready queue: */
159         else if (_pq_alloc(&_readyq, PTHREAD_MIN_PRIORITY, PTHREAD_MAX_PRIORITY) != 0) {
160                 /* Abort this application: */
161                 PANIC("Cannot allocate priority ready queue.");
162         }
163         /* Allocate memory for the thread structure of the initial thread: */
164         else if ((_thread_initial = (pthread_t) malloc(sizeof(struct pthread))) == NULL) {
165                 /*
166                  * Insufficient memory to initialise this application, so
167                  * abort: 
168                  */
169                 PANIC("Cannot allocate memory for initial thread");
170         } else {
171                 /* Zero the global kernel thread structure: */
172                 memset(&_thread_kern_thread, 0, sizeof(struct pthread));
173                 _thread_kern_thread.flags = PTHREAD_FLAGS_PRIVATE;
174                 memset(_thread_initial, 0, sizeof(struct pthread));
175
176                 /* Initialize the waiting and work queues: */
177                 TAILQ_INIT(&_waitingq);
178                 TAILQ_INIT(&_workq);
179
180                 /* Initialize the scheduling switch hook routine: */
181                 _sched_switch_hook = NULL;
182
183                 /* Initialize the thread stack cache: */
184                 SLIST_INIT(&_stackq);
185
186                 /* Create the red zone for the main stack. */
187                 if (mmap((void *) PTHREAD_STACK_TOP
188                          - PTHREAD_STACK_INITIAL,
189                          PTHREAD_STACK_GUARD, 0, MAP_ANON,
190                          -1, 0) == MAP_FAILED) {
191                         PANIC("Cannot allocate red zone for initial thread");
192                 }
193                 
194                 /*
195                  * Write a magic value to the thread structure
196                  * to help identify valid ones:
197                  */
198                 _thread_initial->magic = PTHREAD_MAGIC;
199
200                 /* Default the priority of the initial thread: */
201                 _thread_initial->base_priority = PTHREAD_DEFAULT_PRIORITY;
202                 _thread_initial->active_priority = PTHREAD_DEFAULT_PRIORITY;
203                 _thread_initial->inherited_priority = 0;
204
205                 /* Initialise the state of the initial thread: */
206                 _thread_initial->state = PS_RUNNING;
207
208                 /* Initialise the queue: */
209                 TAILQ_INIT(&(_thread_initial->join_queue));
210
211                 /* Initialize the owned mutex queue and count: */
212                 TAILQ_INIT(&(_thread_initial->mutexq));
213                 _thread_initial->priority_mutex_count = 0;
214
215                 /* Initialise the rest of the fields: */
216                 _thread_initial->poll_data.nfds = 0;
217                 _thread_initial->poll_data.fds = NULL;
218                 _thread_initial->sig_defer_count = 0;
219                 _thread_initial->yield_on_sig_undefer = 0;
220                 _thread_initial->specific_data = NULL;
221                 _thread_initial->cleanup = NULL;
222                 _thread_initial->flags = 0;
223                 _thread_initial->error = 0;
224                 TAILQ_INIT(&_thread_list);
225                 TAILQ_INSERT_HEAD(&_thread_list, _thread_initial, tle);
226                 _thread_run = _thread_initial;
227
228                 /* Initialise the global signal action structure: */
229                 sigfillset(&act.sa_mask);
230                 act.sa_handler = (void (*) ()) _thread_sig_handler;
231                 act.sa_flags = 0;
232
233                 /* Initialize signal handling: */
234                 _thread_sig_init();
235
236                 /* Enter a loop to get the existing signal status: */
237                 for (i = 1; i < NSIG; i++) {
238                         /* Check for signals which cannot be trapped: */
239                         if (i == SIGKILL || i == SIGSTOP) {
240                         }
241
242                         /* Get the signal handler details: */
243                         else if (_thread_sys_sigaction(i, NULL,
244                                                        &_thread_sigact[i - 1]) != 0) {
245                                 /*
246                                  * Abort this process if signal
247                                  * initialisation fails: 
248                                  */
249                                 PANIC("Cannot read signal handler info");
250                         }
251                 }
252
253                 /*
254                  * Install the signal handler for the most important
255                  * signals that the user-thread kernel needs. Actually
256                  * SIGINFO isn't really needed, but it is nice to have.
257                  */
258                 if (_thread_sys_sigaction(_SCHED_SIGNAL, &act, NULL) != 0 ||
259                     _thread_sys_sigaction(SIGINFO,       &act, NULL) != 0 ||
260                     _thread_sys_sigaction(SIGCHLD,       &act, NULL) != 0) {
261                         /*
262                          * Abort this process if signal initialisation fails: 
263                          */
264                         PANIC("Cannot initialise signal handler");
265                 }
266
267                 /* Get the kernel clockrate: */
268                 mib[0] = CTL_KERN;
269                 mib[1] = KERN_CLOCKRATE;
270                 len = sizeof (struct clockinfo);
271                 if (sysctl(mib, 2, &clockinfo, &len, NULL, 0) == 0)
272                         _clock_res_nsec = clockinfo.tick * 1000;
273
274                 /* Get the table size: */
275                 if ((_thread_dtablesize = getdtablesize()) < 0) {
276                         /*
277                          * Cannot get the system defined table size, so abort
278                          * this process. 
279                          */
280                         PANIC("Cannot get dtablesize");
281                 }
282                 /* Allocate memory for the file descriptor table: */
283                 if ((_thread_fd_table = (struct fd_table_entry **) malloc(sizeof(struct fd_table_entry *) * _thread_dtablesize)) == NULL) {
284                         /*
285                          * Cannot allocate memory for the file descriptor
286                          * table, so abort this process. 
287                          */
288                         PANIC("Cannot allocate memory for file descriptor table");
289                 }
290                 /* Allocate memory for the pollfd table: */
291                 if ((_thread_pfd_table = (struct pollfd *) malloc(sizeof(struct pollfd) * _thread_dtablesize)) == NULL) {
292                         /*
293                          * Cannot allocate memory for the file descriptor
294                          * table, so abort this process. 
295                          */
296                         PANIC("Cannot allocate memory for pollfd table");
297                 } else {
298                         /*
299                          * Enter a loop to initialise the file descriptor
300                          * table: 
301                          */
302                         for (i = 0; i < _thread_dtablesize; i++) {
303                                 /* Initialise the file descriptor table: */
304                                 _thread_fd_table[i] = NULL;
305                         }
306
307                         /* Initialize stdio file descriptor table entries: */
308                         if ((_thread_fd_table_init(0) != 0) ||
309                             (_thread_fd_table_init(1) != 0) ||
310                             (_thread_fd_table_init(2) != 0)) {
311                                 PANIC("Cannot initialize stdio file descriptor "
312                                       "table entries");
313                         }
314                 }
315         }
316
317 #ifdef GCC_2_8_MADE_THREAD_AWARE
318         /* Create the thread-specific data for the exception linked list. */
319         if(pthread_key_create(&except_head_key, NULL) != 0)
320                 PANIC("Failed to create thread specific execption head");
321
322         /* Setup the gcc exception handler per thread. */
323         __set_dynamic_handler_allocator( dynamic_allocator_handler_fn );
324 #endif /* GCC_2_8_MADE_THREAD_AWARE */
325
326         /* Initialise the garbage collector mutex and condition variable. */
327         if (pthread_mutex_init(&_gc_mutex,NULL) != 0 ||
328             pthread_cond_init(&_gc_cond,NULL) != 0)
329                 PANIC("Failed to initialise garbage collector mutex or condvar");
330
331         gettimeofday(&kern_inc_prio_time, NULL);
332
333         return;
334 }
335
336 /*
337  * Special start up code for NetBSD/Alpha 
338  */
339 #if     defined(__NetBSD__) && defined(__alpha__)
340 int 
341 main(int argc, char *argv[], char *env);
342
343 int
344 _thread_main(int argc, char *argv[], char *env)
345 {
346         _thread_init();
347         return (main(argc, argv, env));
348 }
349 #endif
350 #else
351 /*
352  * A stub for non-threaded programs.
353  */
354 void
355 _thread_init(void)
356 {
357 }
358 #endif