1 /* vi:ai:et:ts=8 sw=2
2  */
3 /*
4  * wzdftpd - a modular and cool ftp server
5  * Copyright (C) 2002-2004  Pierre Chifflier
6  *
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License
9  * as published by the Free Software Foundation; either version 2
10  * of the License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  * GNU General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
20  *
21  * As a special exemption, Pierre Chifflier
22  * and other respective copyright holders give permission to link this program
23  * with OpenSSL, and distribute the resulting executable, without including
24  * the source code for OpenSSL in the source distribution.
25  */
26 /** \file wzd_threads.c
27   * \brief Threads implementation
28   * \warning This file contains many platform-dependant code
29   */
30 
31 #include "wzd_all.h"
32 
33 #ifndef WZD_USE_PCH
34 
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <errno.h>
39 #include <sys/types.h>
40 
41 #ifdef WIN32
42 # define _WIN32_WINNT    0x500
43 # include <windows.h>
44 #else
45 #include <unistd.h>
46 
47 #include <signal.h>
48 #endif
49 
50 struct wzd_context_t;
51 
52 #include "wzd_log.h"
53 #include "wzd_threads.h"
54 
55 #include "wzd_debug.h"
56 
57 #else /* WZD_USE_PCH */
58 #ifdef WIN32
59 #define _WIN32_WINNT    0x500
60 #include <windows.h>
61 #endif
62 #endif /* WZD_USE_PCH */
63 
64 #ifdef HAVE_PTHREAD
65 
66 struct thread_key_t {
67   pthread_key_t key;
68 };
69 
70 #else /* HAVE_PTHREAD */
71 
72 struct thread_key_t {
73   DWORD key;
74 };
75 
76 #endif /* HAVE_PTHREAD*/
77 
78 /** \brief Create a new thread
79  *
80  * This function create a new thread, using native threads on Windows and pthreads
81  * elsewhere. The new thread is started immediatly, unless specific attributes
82  * have been defined.
83  *
84  * \param[out] thread location where the new thread id will be stored
85  * \param[in] attr thread specific attributes
86  * \param[in] start_routine the function to execute in the new thread
87  * \param[in] arg an argument to be passed to start_routine
88  */
wzd_thread_create(wzd_thread_t * thread,wzd_thread_attr_t * attr,void * (start_routine)(void *),void * arg)89 int wzd_thread_create(wzd_thread_t * thread, wzd_thread_attr_t * attr, void * (start_routine)(void *), void * arg)
90 {
91 #ifndef WIN32
92   int ret;
93 
94   {
95     /* block signals so that other threads possibly created later (for ex.
96      * in modules) do not receive signals like SIGINT
97      */
98     sigset_t oldmask, newmask;
99     sigfillset(&newmask);
100     ret = pthread_sigmask(SIG_BLOCK,&newmask,&oldmask);
101     WZD_ASSERT( ret == 0 );
102   }
103 
104   ret =  pthread_create( & thread->_t, & attr->_a, start_routine, arg);
105 
106   {
107     /* restore signals so we can be stopped with SIGINT or restarted with SIGHUP */
108     sigset_t oldmask, newmask;
109     sigfillset(&newmask);
110     ret = pthread_sigmask(SIG_UNBLOCK,&newmask,&oldmask);
111     WZD_ASSERT( ret == 0 );
112   }
113 
114   return ret;
115 #else
116   unsigned long threadID;
117 
118   thread->_t = CreateThread( NULL /* not supported yet */, 0, (LPTHREAD_START_ROUTINE)start_routine, arg, 0 /* creation flags */, &threadID);
119 
120   return (thread->_v == NULL);
121 #endif
122 }
123 
124 /** \brief Initialize an empty wzd_thread_attr_t structure
125  *
126  * \param[out] attr pointer to the new attributes structure
127  *
128  * \return 0 if ok
129  */
wzd_thread_attr_init(wzd_thread_attr_t * attr)130 int wzd_thread_attr_init(wzd_thread_attr_t * attr)
131 {
132 #ifndef WIN32
133   return pthread_attr_init( & attr->_a );
134 #else
135   attr->_v = NULL;
136   return 0;
137 #endif
138 }
139 
140 /** \brief Free resources used by a wzd_thread_attr_t structure
141  *
142  * \param[in] attr pointer to the attributes structure
143  *
144  * \return 0 if ok
145  */
wzd_thread_attr_destroy(wzd_thread_attr_t * attr)146 int wzd_thread_attr_destroy(wzd_thread_attr_t * attr)
147 {
148 #ifndef WIN32
149   return pthread_attr_destroy( & attr->_a );
150 #else
151   attr->_v = NULL;
152   return 0;
153 #endif
154 }
155 
156 /** \brief Set thread attribute to detachable state
157  *
158  * Resources used by a detached thread are freed immediatly when
159  * the thread exits, and wzd_thread_join can't be used to get the
160  * return code.
161  *
162  * \param[in] attr attributes structure
163  *
164  * \return 0 if ok
165  */
wzd_thread_attr_set_detached(wzd_thread_attr_t * attr)166 int wzd_thread_attr_set_detached(wzd_thread_attr_t * attr)
167 {
168 #ifndef WIN32
169   return pthread_attr_setdetachstate( & attr->_a, PTHREAD_CREATE_DETACHED);
170 #else
171   return 0;
172 #endif
173 }
174 
175 /** \brief Wait for termination of another thread
176  *
177  * Wait indefinitly, until thread terminates. The return code is stored
178  * in thread_return, and the thread can be freed after.
179  *
180  * \param[in] thread the thread id to wait for
181  * \param[out] thread_return the return value of thread
182  *
183  * \return 0 if ok
184  */
wzd_thread_join(wzd_thread_t * thread,void ** thread_return)185 int wzd_thread_join(wzd_thread_t * thread, void ** thread_return)
186 {
187 #ifndef WIN32
188   return pthread_join(thread->_t, thread_return);
189 #else
190 
191   if (WaitForSingleObject(thread->_t, INFINITE) != WAIT_OBJECT_0)
192   {
193     out_log(LEVEL_CRITICAL, "Thread join failed.");
194     CloseHandle(thread->_t);
195 
196     return -1;
197   }
198   CloseHandle(thread->_t);
199 
200   return 0;
201 #endif
202 }
203 
204 /** \brief Cancel thread by sending a signal
205  *
206  * \param[in] thread the thread to cancel
207  */
wzd_thread_cancel(wzd_thread_t * thread)208 int wzd_thread_cancel(wzd_thread_t * thread)
209 {
210 #ifndef WIN32
211   return pthread_cancel(thread->_t);
212 #else
213   /** \todo use pthread_kill() equivalent for windows */
214   out_log(LEVEL_CRITICAL, "Not Yet Implemented : wzd_thread_cancel\n");
215   return -1;
216 #endif
217 }
218 
219 /** \brief Allocate a new thread-local storage
220  *
221  * If a TLS is already allocated, do nothing
222  *
223  * \return
224  * - a unique identifier to a thread specific data area (TSD) if ok
225  * - NULL on error
226  */
wzd_tls_allocate()227 struct thread_key_t * wzd_tls_allocate()
228 {
229   struct thread_key_t * thread_key = NULL;
230   thread_key = malloc(sizeof(struct thread_key_t));
231 #ifdef HAVE_PTHREAD
232   {
233     int ret;
234     ret = pthread_key_create(&thread_key->key,NULL);
235   }
236 #else
237   thread_key->key = TlsAlloc();
238 #endif
239   return thread_key;
240 }
241 
242 /** \brief Free thread-local storage but not key
243  *
244  * \param[in] thread_key key to TSD
245  * \return 0 if ok
246  */
wzd_tls_remove(struct thread_key_t * thread_key)247 int wzd_tls_remove(struct thread_key_t * thread_key)
248 {
249   int ret;
250   if (thread_key != NULL) {
251 #ifdef HAVE_PTHREAD
252     ret = pthread_key_delete(thread_key->key);
253 #else
254     ret = TlsFree(thread_key->key);
255 #endif
256   }
257   return 0;
258 }
259 
260 /** \brief Free thread-local storage and key
261  *
262  * \param[in] thread_key key to TSD
263  * \return 0 if ok
264  */
wzd_tls_free(struct thread_key_t * thread_key)265 int wzd_tls_free(struct thread_key_t * thread_key)
266 {
267   int ret;
268   if (thread_key != NULL) {
269 #ifdef HAVE_PTHREAD
270     ret = pthread_key_delete(thread_key->key);
271 #else
272     ret = TlsFree(thread_key->key);
273 #endif
274     free(thread_key);
275     thread_key = NULL;
276   }
277   return 0;
278 }
279 
280 /** \brief Store value in TLS
281  *
282  * \param[in] thread_key key to TSD
283  * \param[in] data_ptr pointer to the data which will be duplicated for the thread
284  * \return 0 if ok
285  */
wzd_tls_setspecific(struct thread_key_t * thread_key,const void * data_ptr)286 int wzd_tls_setspecific(struct thread_key_t * thread_key, const void * data_ptr)
287 {
288 #ifdef HAVE_PTHREAD
289   return pthread_setspecific(thread_key->key,data_ptr);
290 #else
291   return TlsSetValue(thread_key->key,data_ptr);
292 #endif
293 }
294 
295 /** \brief Get value from TLS
296  *
297  * \param[in] thread_key key to TSD
298  * \return 0 if ok
299  */
wzd_tls_getspecific(struct thread_key_t * thread_key)300 void * wzd_tls_getspecific(struct thread_key_t * thread_key)
301 {
302 #ifdef HAVE_PTHREAD
303   return pthread_getspecific(thread_key->key);
304 #else
305   return TlsGetValue(thread_key->key);
306 #endif
307 }
308 
309