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