1 /*
2   This file is part of libmicrohttpd
3   Copyright (C) 2016 Karlson2k (Evgeny Grin)
4 
5   This library is free software; you can redistribute it and/or
6   modify it under the terms of the GNU Lesser General Public
7   License as published by the Free Software Foundation; either
8   version 2.1 of the License, or (at your option) any later version.
9 
10   This library is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   Lesser General Public License for more details.
14 
15   You should have received a copy of the GNU Lesser General Public
16   License along with this library; if not, write to the Free Software
17   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
18 
19 */
20 
21 /**
22  * @file microhttpd/mhd_threads.h
23  * @brief  Header for platform-independent threads abstraction
24  * @author Karlson2k (Evgeny Grin)
25  *
26  * Provides basic abstraction for threads.
27  * Any functions can be implemented as macro on some platforms
28  * unless explicitly marked otherwise.
29  * Any function argument can be skipped in macro, so avoid
30  * variable modification in function parameters.
31  *
32  * @warning Unlike pthread functions, most of functions return
33  *          nonzero on success.
34  */
35 
36 #ifndef MHD_THREADS_H
37 #define MHD_THREADS_H 1
38 
39 #include "mhd_options.h"
40 #ifdef HAVE_STDDEF_H
41 #  include <stddef.h> /* for size_t */
42 #elif defined(HAVE_STDLIB_H)
43 #  include <stdlib.h> /* for size_t */
44 #else /* ! HAVE_STDLIB_H */
45 #  include <stdio.h>  /* for size_t */
46 #endif /* ! HAVE_STDLIB_H */
47 
48 #if defined(MHD_USE_POSIX_THREADS)
49 #  undef HAVE_CONFIG_H
50 #  include <pthread.h>
51 #  define HAVE_CONFIG_H 1
52 #  ifndef MHD_USE_THREADS
53 #    define MHD_USE_THREADS 1
54 #  endif
55 #elif defined(MHD_USE_W32_THREADS)
56 #  ifndef WIN32_LEAN_AND_MEAN
57 #    define WIN32_LEAN_AND_MEAN 1
58 #  endif /* !WIN32_LEAN_AND_MEAN */
59 #  include <windows.h>
60 #  ifndef MHD_USE_THREADS
61 #    define MHD_USE_THREADS 1
62 #  endif
63 #else
64 #  error No threading API is available.
65 #endif
66 
67 #ifndef MHD_NO_THREAD_NAMES
68 #  if defined(MHD_USE_POSIX_THREADS)
69 #    if defined(HAVE_PTHREAD_SETNAME_NP_GNU) || \
70   defined(HAVE_PTHREAD_SET_NAME_NP_FREEBSD) || \
71   defined(HAVE_PTHREAD_SETNAME_NP_DARWIN) || \
72   defined(HAVE_PTHREAD_SETNAME_NP_NETBSD) || \
73   defined(HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD) || \
74   defined(HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI)
75 #      define MHD_USE_THREAD_NAME_
76 #    endif /* HAVE_PTHREAD_SETNAME_NP */
77 #  elif defined(MHD_USE_W32_THREADS)
78 #    ifdef _MSC_FULL_VER
79 /* Thread names only available with VC compiler */
80 #      define MHD_USE_THREAD_NAME_
81 #    endif /* _MSC_FULL_VER */
82 #  endif
83 #endif
84 
85 #if defined(MHD_USE_POSIX_THREADS)
86 typedef pthread_t MHD_thread_handle_;
87 #elif defined(MHD_USE_W32_THREADS)
88 typedef HANDLE MHD_thread_handle_;
89 #endif
90 
91 #if defined(MHD_USE_POSIX_THREADS)
92 #  define MHD_THRD_RTRN_TYPE_ void*
93 #  define MHD_THRD_CALL_SPEC_
94 #elif defined(MHD_USE_W32_THREADS)
95 #  define MHD_THRD_RTRN_TYPE_ unsigned
96 #  define MHD_THRD_CALL_SPEC_ __stdcall
97 #endif
98 
99 #if defined(MHD_USE_POSIX_THREADS)
100 typedef pthread_t MHD_thread_ID_;
101 #elif defined(MHD_USE_W32_THREADS)
102 typedef DWORD MHD_thread_ID_;
103 #endif
104 
105 /* Depending on implementation, pthread_create() MAY set thread ID into
106  * provided pointer and after it start thread OR start thread and after
107  * it set thread ID. In the latter case, to avoid data races, additional
108  * pthread_self() call is required in thread routine. If some platform
109  * is known for setting thread ID BEFORE starting thread macro
110  * MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD could be defined
111  * to save some resources. */
112 /* * handle - must be valid when other thread knows that particular thread
113      is started.
114    * ID     - must be valid when code is executed inside thread */
115 #if defined(MHD_USE_POSIX_THREADS)
116 #  ifdef MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD
117 union _MHD_thread_handle_ID_
118 {
119   MHD_thread_handle_ handle;    /**< To be used in other threads */
120   MHD_thread_ID_ ID;            /**< To be used in thread itself */
121 };
122 typedef union _MHD_thread_handle_ID_ MHD_thread_handle_ID_;
123 #  else  /* ! MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD */
124 struct _MHD_thread_handle_ID_
125 {
126   MHD_thread_handle_ handle;    /**< To be used in other threads */
127   MHD_thread_ID_ ID;            /**< To be used in thread itself */
128 };
129 typedef struct _MHD_thread_handle_ID_ MHD_thread_handle_ID_;
130 #  endif /* ! MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD */
131 #elif defined(MHD_USE_W32_THREADS)
132 struct _MHD_thread_handle_ID_
133 {
134   MHD_thread_handle_ handle;    /**< To be used in other threads */
135   MHD_thread_ID_ ID;            /**< To be used in thread itself */
136 };
137 typedef struct _MHD_thread_handle_ID_ MHD_thread_handle_ID_;
138 #endif
139 
140 #if defined(MHD_USE_POSIX_THREADS)
141 /**
142  * Wait until specified thread is ended and free thread handle on success.
143  * @param thread handle to watch
144  * @return nonzero on success, zero otherwise
145  */
146 #define MHD_join_thread_(thread) (! pthread_join ((thread), NULL))
147 #elif defined(MHD_USE_W32_THREADS)
148 /**
149  * Wait until specified thread is ended and free thread handle on success.
150  * @param thread handle to watch
151  * @return nonzero on success, zero otherwise
152  */
153 #define MHD_join_thread_(thread) \
154   ( (WAIT_OBJECT_0 == WaitForSingleObject ( (thread), INFINITE)) ? \
155     (CloseHandle ( (thread)), ! 0) : 0 )
156 #endif
157 
158 #if defined(MHD_USE_POSIX_THREADS)
159 /**
160  * Check whether provided thread ID match current thread.
161  * @param ID thread ID to match
162  * @return nonzero on match, zero otherwise
163  */
164 #define MHD_thread_ID_match_current_(pid) \
165           (pthread_equal ((pid).ID, pthread_self ()))
166 #elif defined(MHD_USE_W32_THREADS)
167 /**
168  * Check whether provided thread ID match current thread.
169  * @param ID thread ID to match
170  * @return nonzero on match, zero otherwise
171  */
172 #define MHD_thread_ID_match_current_(pid) (GetCurrentThreadId () == (pid).ID)
173 #endif
174 
175 #if defined(MHD_USE_POSIX_THREADS)
176 #  ifdef MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD
177 /**
178  * Initialise thread ID.
179  * @param thread_handle_ID_ptr pointer to thread handle-ID
180  */
181 #define MHD_thread_init_(thread_handle_ID_ptr) (void) 0
182 #  else  /* ! MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD */
183 /**
184  * Initialise thread ID.
185  * @param thread_handle_ID_ptr pointer to thread handle-ID
186  */
187 #define MHD_thread_init_(thread_handle_ID_ptr) ((thread_handle_ID_ptr)->ID = \
188                                                   pthread_self ())
189 #  endif /* ! MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD */
190 #elif defined(MHD_USE_W32_THREADS)
191 /**
192  * Initialise thread ID.
193  * @param thread_handle_ID_ptr pointer to thread handle-ID
194  */
195 #define MHD_thread_init_(thread_handle_ID_ptr) ((thread_handle_ID_ptr)->ID = \
196                                                   GetCurrentThreadId ())
197 #endif
198 
199 /**
200  * Signature of main function for a thread.
201  *
202  * @param cls closure argument for the function
203  * @return termination code from the thread
204  */
205 typedef MHD_THRD_RTRN_TYPE_
206 (MHD_THRD_CALL_SPEC_ *MHD_THREAD_START_ROUTINE_)(void *cls);
207 
208 
209 /**
210  * Create a thread and set the attributes according to our options.
211  *
212  * If thread is created, thread handle must be freed by MHD_join_thread_().
213  *
214  * @param thread        handle to initialize
215  * @param stack_size    size of stack for new thread, 0 for default
216  * @param start_routine main function of thread
217  * @param arg argument  for start_routine
218  * @return non-zero on success; zero otherwise
219  */
220 int
221 MHD_create_thread_ (MHD_thread_handle_ID_ *thread,
222                     size_t stack_size,
223                     MHD_THREAD_START_ROUTINE_ start_routine,
224                     void *arg);
225 
226 #ifndef MHD_USE_THREAD_NAME_
227 #define MHD_create_named_thread_(t,n,s,r,a) MHD_create_thread_ ((t),(s),(r),(a))
228 #else  /* MHD_USE_THREAD_NAME_ */
229 /**
230  * Create a named thread and set the attributes according to our options.
231  *
232  * @param thread        handle to initialize
233  * @param thread_name   name for new thread
234  * @param stack_size    size of stack for new thread, 0 for default
235  * @param start_routine main function of thread
236  * @param arg argument  for start_routine
237  * @return non-zero on success; zero otherwise
238  */
239 int
240 MHD_create_named_thread_ (MHD_thread_handle_ID_ *thread,
241                           const char *thread_name,
242                           size_t stack_size,
243                           MHD_THREAD_START_ROUTINE_ start_routine,
244                           void *arg);
245 
246 #endif /* MHD_USE_THREAD_NAME_ */
247 
248 #endif /* ! MHD_THREADS_H */
249