1 /*	$OpenBSD: uthread_gc.c,v 1.14 2004/04/06 03:56:39 marc Exp $	*/
2 /*
3  * Copyright (c) 1998 John Birrell <jb@cimlogic.com.au>
4  * All rights reserved.
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. All advertising materials mentioning features or use of this software
15  *    must display the following acknowledgement:
16  *	This product includes software developed by John Birrell.
17  * 4. Neither the name of the author nor the names of any co-contributors
18  *    may be used to endorse or promote products derived from this software
19  *    without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY JOHN BIRRELL AND CONTRIBUTORS ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  *
33  * $FreeBSD: uthread_gc.c,v 1.10 1999/08/28 00:03:34 peter Exp $
34  *
35  * Garbage collector thread. Frees memory allocated for dead threads.
36  *
37  */
38 #include <errno.h>
39 #include <stdlib.h>
40 #include <time.h>
41 #include <unistd.h>
42 #include <sys/types.h>
43 #include <sys/types.h>
44 #include <sys/mman.h>
45 #include <pthread.h>
46 #include "pthread_private.h"
47 
48 pthread_addr_t
_thread_gc(pthread_addr_t arg)49 _thread_gc(pthread_addr_t arg)
50 {
51 	struct pthread	*curthread = _get_curthread();
52 	int		f_debug;
53 	int		f_done = 0;
54 	int		ret;
55 	sigset_t	mask;
56 	pthread_t	pthread;
57 	pthread_t	pthread_cln;
58 	struct timespec	abstime;
59 	void		*p_stack;
60 
61 	/* Block all signals */
62 	sigfillset(&mask);
63 	pthread_sigmask(SIG_BLOCK, &mask, NULL);
64 
65 	/* Mark this thread as a library thread (not a user thread). */
66 	curthread->flags |= PTHREAD_FLAGS_PRIVATE;
67 
68 	/* Set a debug flag based on an environment variable. */
69 	f_debug = (getenv("LIBPTHREAD_DEBUG") != NULL);
70 
71 	/* Set the name of this thread. */
72 	pthread_set_name_np(curthread, (char *)"GC");
73 
74 	while (!f_done) {
75 		/* Check if debugging this application. */
76 		if (f_debug)
77 			/* Dump thread info to file. */
78 			_thread_dump_info();
79 
80 		/*
81 		 * Defer signals to protect the scheduling queues from
82 		 * access by the signal handler:
83 		 */
84 		_thread_kern_sig_defer();
85 
86 		/* Check if this is the last running thread: */
87 		if (TAILQ_FIRST(&_thread_list) == curthread &&
88 		    TAILQ_NEXT(curthread, tle) == NULL)
89 			/*
90 			 * This is the last thread, so it can exit
91 			 * now.
92 			 */
93 			f_done = 1;
94 
95 		/*
96 		 * Undefer and handle pending signals, yielding if
97 		 * necessary:
98 		 */
99 		_thread_kern_sig_undefer();
100 
101 		/* No stack of thread structure to free yet: */
102 		p_stack = NULL;
103 		pthread_cln = NULL;
104 
105 		/*
106 		 * Lock the garbage collector mutex which ensures that
107 		 * this thread sees another thread exit:
108 		 */
109 		if (pthread_mutex_lock(&_gc_mutex) != 0)
110 			PANIC("Cannot lock gc mutex");
111 
112 		/*
113 		 * Enter a loop to search for the first dead thread that
114 		 * has memory to free.
115 		 */
116 		for (pthread = TAILQ_FIRST(&_dead_list);
117 		     p_stack == NULL && pthread_cln == NULL && pthread != NULL;
118 		     pthread = TAILQ_NEXT(pthread, dle)) {
119 			/* Check if the initial thread: */
120 			if (pthread == _thread_initial) {
121 				/* Don't destroy the initial thread. */
122 			}
123 			/*
124 			 * Check if this thread has detached:
125 			 */
126 			else if ((pthread->attr.flags &
127 			    PTHREAD_DETACHED) != 0) {
128 				/* Remove this thread from the dead list: */
129 				TAILQ_REMOVE(&_dead_list, pthread, dle);
130 
131 				/*
132 				 * Point to the stack structure that must
133 				 * be freed outside the locks:
134 				 */
135 				if (pthread->stack != NULL) {
136 					p_stack = pthread->stack;
137 					pthread->stack = NULL;
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 				 * But we can destroy its stack.
152 				 */
153 			        if (pthread->stack != NULL) {
154 					p_stack = pthread->stack;
155 					pthread->stack = NULL;
156 				}
157 			}
158 		}
159 
160 		/*
161 		 * Check if this is not the last thread and there is no
162 		 * memory to free this time around.
163 		 */
164 		if (!f_done && p_stack == NULL && pthread_cln == NULL) {
165 			/* Get the current time. */
166 			if (clock_gettime(CLOCK_REALTIME,&abstime) != 0)
167 				PANIC("gc cannot get time");
168 
169 			/*
170 			 * Do a backup poll in 10 seconds if no threads
171 			 * die before then.
172 			 */
173 			abstime.tv_sec += 10;
174 
175 			/*
176 			 * Wait for a signal from a dying thread or a
177 			 * timeout (for a backup poll).
178 			 */
179 			if ((ret = pthread_cond_timedwait(&_gc_cond,
180 			    &_gc_mutex, &abstime)) != 0 && ret != ETIMEDOUT)
181 				PANIC("gc cannot wait for a signal");
182 		}
183 
184 		/* Unlock the garbage collector mutex: */
185 		if (pthread_mutex_unlock(&_gc_mutex) != 0)
186 			PANIC("Cannot unlock gc mutex");
187 
188 		/*
189 		 * If there is memory to free, do it now. The call to
190 		 * free() might block, so this must be done outside the
191 		 * locks.
192 		 */
193 		if (p_stack != NULL)
194 			/* Free the stack storage. */
195 			_thread_stack_free(p_stack);
196 
197 		if (pthread_cln != NULL) {
198 			if (pthread_cln->name != NULL) {
199 				/* Free the thread name string. */
200 				free(pthread_cln->name);
201 			}
202 			/*
203 			 * Free the memory allocated for the thread
204 			 * structure.
205 			 */
206 			if (pthread_cln->poll_data.fds != NULL)
207 				free(pthread_cln->poll_data.fds);
208 
209 			if (pthread_cln->specific_data != NULL)
210 				free(pthread_cln->specific_data);
211 
212 			free(pthread_cln);
213 		}
214 	}
215 	return (NULL);
216 }
217