]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - lib/libc_r/uthread/uthread_gc.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / lib / libc_r / uthread / uthread_gc.c
1 /*
2  * Copyright (c) 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. Neither the name of the author nor the names of any co-contributors
14  *    may be used to endorse or promote products derived from this software
15  *    without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  *
31  * Garbage collector thread. Frees memory allocated for dead threads.
32  *
33  */
34 #include <sys/param.h>
35 #include <errno.h>
36 #include <time.h>
37 #include <stdlib.h>
38 #include <unistd.h>
39 #include <sys/types.h>
40 #include "namespace.h"
41 #include <pthread.h>
42 #include "un-namespace.h"
43 #include "pthread_private.h"
44
45 pthread_addr_t
46 _thread_gc(pthread_addr_t arg)
47 {
48         struct pthread  *curthread = _get_curthread();
49         int             f_debug;
50         int             f_done = 0;
51         int             ret;
52         sigset_t        mask;
53         pthread_t       pthread;
54         pthread_t       pthread_cln;
55         struct timespec abstime;
56         void            *p_stack;
57
58         /* Block all signals */
59         sigfillset(&mask);
60         _pthread_sigmask(SIG_BLOCK, &mask, NULL);
61
62         /* Mark this thread as a library thread (not a user thread). */
63         curthread->flags |= PTHREAD_FLAGS_PRIVATE;
64
65         /* Set a debug flag based on an environment variable. */
66         f_debug = (getenv("LIBC_R_DEBUG") != NULL);
67
68         /* Set the name of this thread. */
69         pthread_set_name_np(curthread,"GC");
70
71         while (!f_done) {
72                 /* Check if debugging this application. */
73                 if (f_debug)
74                         /* Dump thread info to file. */
75                         _thread_dump_info();
76
77                 /*
78                  * Defer signals to protect the scheduling queues from
79                  * access by the signal handler:
80                  */
81                 _thread_kern_sig_defer();
82
83                 /* Check if this is the last running thread: */
84                 if (TAILQ_FIRST(&_thread_list) == curthread &&
85                     TAILQ_NEXT(curthread, tle) == NULL)
86                         /*
87                          * This is the last thread, so it can exit
88                          * now.
89                          */
90                         f_done = 1;
91
92                 /*
93                  * Undefer and handle pending signals, yielding if
94                  * necessary:
95                  */
96                 _thread_kern_sig_undefer();
97
98                 /* No stack of thread structure to free yet: */
99                 p_stack = NULL;
100                 pthread_cln = NULL;
101
102                 /*
103                  * Lock the garbage collector mutex which ensures that
104                  * this thread sees another thread exit:
105                  */
106                 if (_pthread_mutex_lock(&_gc_mutex) != 0)
107                         PANIC("Cannot lock gc mutex");
108
109                 /*
110                  * Enter a loop to search for the first dead thread that
111                  * has memory to free.
112                  */
113                 for (pthread = TAILQ_FIRST(&_dead_list);
114                      p_stack == NULL && pthread_cln == NULL && pthread != NULL;
115                      pthread = TAILQ_NEXT(pthread, dle)) {
116                         /* Check if the initial thread: */
117                         if (pthread == _thread_initial) {
118                                 /* Don't destroy the initial thread. */
119                         }
120                         /*
121                          * Check if this thread has detached:
122                          */
123                         else if ((pthread->attr.flags &
124                             PTHREAD_DETACHED) != 0) {
125                                 /* Remove this thread from the dead list: */
126                                 TAILQ_REMOVE(&_dead_list, pthread, dle);
127
128                                 /*
129                                  * Check if the stack was not specified by
130                                  * the caller to pthread_create() and has not
131                                  * been destroyed yet: 
132                                  */
133                                 if (pthread->attr.stackaddr_attr == NULL &&
134                                     pthread->stack != NULL) {
135                                         _thread_stack_free(pthread->stack,
136                                             pthread->attr.stacksize_attr,
137                                             pthread->attr.guardsize_attr);
138                                 }
139
140                                 /*
141                                  * Point to the thread structure that must
142                                  * be freed outside the locks:
143                                  */
144                                 pthread_cln = pthread;
145
146                         } else {
147                                 /*
148                                  * This thread has not detached, so do
149                                  * not destroy it.
150                                  *
151                                  * Check if the stack was not specified by
152                                  * the caller to pthread_create() and has not
153                                  * been destroyed yet: 
154                                  */
155                                 if (pthread->attr.stackaddr_attr == NULL &&
156                                     pthread->stack != NULL) {
157                                         _thread_stack_free(pthread->stack,
158                                             pthread->attr.stacksize_attr,
159                                             pthread->attr.guardsize_attr);
160
161                                         /*
162                                          * NULL the stack pointer now that the
163                                          * memory has been freed:
164                                          */
165                                         pthread->stack = NULL;
166                                 }
167                         }
168                 }
169
170                 /*
171                  * Check if this is not the last thread and there is no
172                  * memory to free this time around.
173                  */
174                 if (!f_done && p_stack == NULL && pthread_cln == NULL) {
175                         /* Get the current time. */
176                         if (clock_gettime(CLOCK_REALTIME,&abstime) != 0)
177                                 PANIC("gc cannot get time");
178
179                         /*
180                          * Do a backup poll in 10 seconds if no threads
181                          * die before then.
182                          */
183                         abstime.tv_sec += 10;
184
185                         /*
186                          * Wait for a signal from a dying thread or a
187                          * timeout (for a backup poll).
188                          */
189                         if ((ret = _pthread_cond_timedwait(&_gc_cond,
190                             &_gc_mutex, &abstime)) != 0 && ret != ETIMEDOUT)
191                                 PANIC("gc cannot wait for a signal");
192                 }
193
194                 /* Unlock the garbage collector mutex: */
195                 if (_pthread_mutex_unlock(&_gc_mutex) != 0)
196                         PANIC("Cannot unlock gc mutex");
197
198                 /*
199                  * If there is memory to free, do it now. The call to
200                  * free() might block, so this must be done outside the
201                  * locks.
202                  */
203                 if (p_stack != NULL)
204                         free(p_stack);
205                 if (pthread_cln != NULL) {
206                         if (pthread_cln->name != NULL) {
207                                 /* Free the thread name string. */
208                                 free(pthread_cln->name);
209                         }
210                         /*
211                          * Free the memory allocated for the thread
212                          * structure.
213                          */
214                         free(pthread_cln);
215                 }
216         }
217         return (NULL);
218 }