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 #else  /* ! HAVE_STDDEF_H */
43 #  include <stdlib.h> /* for size_t */
44 #endif /* ! HAVE_STDDEF_H */
45 
46 #if defined(MHD_USE_POSIX_THREADS)
47 #  undef HAVE_CONFIG_H
48 #  include <pthread.h>
49 #  define HAVE_CONFIG_H 1
50 #elif defined(MHD_USE_W32_THREADS)
51 #  ifndef WIN32_LEAN_AND_MEAN
52 #    define WIN32_LEAN_AND_MEAN 1
53 #  endif /* !WIN32_LEAN_AND_MEAN */
54 #  include <windows.h>
55 #else
56 #  error No threading API is available.
57 #endif
58 
59 #ifndef MHD_NO_THREAD_NAMES
60 #  if defined(MHD_USE_POSIX_THREADS)
61 #    if defined(HAVE_PTHREAD_SETNAME_NP_GNU) || \
62   defined(HAVE_PTHREAD_SET_NAME_NP_FREEBSD) || \
63   defined(HAVE_PTHREAD_SETNAME_NP_DARWIN) || \
64   defined(HAVE_PTHREAD_SETNAME_NP_NETBSD) || \
65   defined(HAVE_PTHREAD_ATTR_SETNAME_NP_NETBSD) || \
66   defined(HAVE_PTHREAD_ATTR_SETNAME_NP_IBMI)
67 #      define MHD_USE_THREAD_NAME_
68 #    endif /* HAVE_PTHREAD_SETNAME_NP */
69 #  elif defined(MHD_USE_W32_THREADS)
70 #    ifdef _MSC_FULL_VER
71 /* Thread names only available with VC compiler */
72 #      define MHD_USE_THREAD_NAME_
73 #    endif /* _MSC_FULL_VER */
74 #  endif
75 #endif
76 
77 #if defined(MHD_USE_POSIX_THREADS)
78 typedef pthread_t MHD_thread_handle_;
79 #elif defined(MHD_USE_W32_THREADS)
80 typedef HANDLE MHD_thread_handle_;
81 #endif
82 
83 #if defined(MHD_USE_POSIX_THREADS)
84 #  define MHD_THRD_RTRN_TYPE_ void*
85 #  define MHD_THRD_CALL_SPEC_
86 #elif defined(MHD_USE_W32_THREADS)
87 #  define MHD_THRD_RTRN_TYPE_ unsigned
88 #  define MHD_THRD_CALL_SPEC_ __stdcall
89 #endif
90 
91 #if defined(MHD_USE_POSIX_THREADS)
92 typedef pthread_t MHD_thread_ID_;
93 #elif defined(MHD_USE_W32_THREADS)
94 typedef DWORD MHD_thread_ID_;
95 #endif
96 
97 /* Depending on implementation, pthread_create() MAY set thread ID into
98  * provided pointer and after it start thread OR start thread and after
99  * if set thread ID. In latter case, to avoid data races, additional
100  * pthread_self() call is required in thread routine. Is some platform
101  * is known for setting thread ID BEFORE starting thread macro
102  * MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD could be defined
103  * to save some resources. */
104 #if defined(MHD_USE_POSIX_THREADS)
105 #  ifdef MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD
106 union _MHD_thread_handle_ID_
107 {
108   MHD_thread_handle_ handle;    /**< To be used in other threads */
109   MHD_thread_ID_ ID;            /**< To be used in thread itself */
110 };
111 typedef union _MHD_thread_handle_ID_ MHD_thread_handle_ID_;
112 #  else  /* ! MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD */
113 struct _MHD_thread_handle_ID_
114 {
115   MHD_thread_handle_ handle;    /**< To be used in other threads */
116   MHD_thread_ID_ ID;            /**< To be used in thread itself */
117 };
118 typedef struct _MHD_thread_handle_ID_ MHD_thread_handle_ID_;
119 #  endif /* ! MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD */
120 #elif defined(MHD_USE_W32_THREADS)
121 struct _MHD_thread_handle_ID_
122 {
123   MHD_thread_handle_ handle;    /**< To be used in other threads */
124   MHD_thread_ID_ ID;            /**< To be used in thread itself */
125 };
126 typedef struct _MHD_thread_handle_ID_ MHD_thread_handle_ID_;
127 #endif
128 
129 #if defined(MHD_USE_POSIX_THREADS)
130 /**
131  * Wait until specified thread is ended and free thread handle on success.
132  * @param thread handle to watch
133  * @return nonzero on success, zero otherwise
134  */
135 #define MHD_join_thread_(thread) (! pthread_join ((thread), NULL))
136 #elif defined(MHD_USE_W32_THREADS)
137 /**
138  * Wait until specified thread is ended and free thread handle on success.
139  * @param thread handle to watch
140  * @return nonzero on success, zero otherwise
141  */
142 #define MHD_join_thread_(thread) (WAIT_OBJECT_0 == WaitForSingleObject ( \
143                                     (thread), INFINITE) ? (CloseHandle ( \
144                                                              (thread)), ! 0) : \
145                                   0)
146 #endif
147 
148 #if defined(MHD_USE_POSIX_THREADS)
149 /**
150  * Check whether provided thread ID match current thread.
151  * @param ID thread ID to match
152  * @return nonzero on match, zero otherwise
153  */
154 #define MHD_thread_ID_match_current_(ID) (pthread_equal ((ID), pthread_self ()))
155 #elif defined(MHD_USE_W32_THREADS)
156 /**
157  * Check whether provided thread ID match current thread.
158  * @param ID thread ID to match
159  * @return nonzero on match, zero otherwise
160  */
161 #define MHD_thread_ID_match_current_(ID) (GetCurrentThreadId () == (ID))
162 #endif
163 
164 #if defined(MHD_USE_POSIX_THREADS)
165 #  ifdef MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD
166 /**
167  * Initialise thread ID.
168  * @param thread_handle_ID_ptr pointer to thread handle-ID
169  */
170 #define MHD_thread_init_(thread_handle_ID_ptr) (void) 0
171 #  else  /* ! MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD */
172 /**
173  * Initialise thread ID.
174  * @param thread_handle_ID_ptr pointer to thread handle-ID
175  */
176 #define MHD_thread_init_(thread_handle_ID_ptr) ((thread_handle_ID_ptr)->ID = \
177                                                   pthread_self ())
178 #  endif /* ! MHD_PTHREAD_CREATE__SET_ID_BEFORE_START_THREAD */
179 #elif defined(MHD_USE_W32_THREADS)
180 /**
181  * Initialise thread ID.
182  * @param thread_handle_ID_ptr pointer to thread handle-ID
183  */
184 #define MHD_thread_init_(thread_handle_ID_ptr) ((thread_handle_ID_ptr)->ID = \
185                                                   GetCurrentThreadId ())
186 #endif
187 
188 /**
189  * Signature of main function for a thread.
190  *
191  * @param cls closure argument for the function
192  * @return termination code from the thread
193  */
194 typedef MHD_THRD_RTRN_TYPE_
195 (MHD_THRD_CALL_SPEC_ *MHD_THREAD_START_ROUTINE_)(void *cls);
196 
197 
198 /**
199  * Create a thread and set the attributes according to our options.
200  *
201  * If thread is created, thread handle must be freed by MHD_join_thread_().
202  *
203  * @param thread        handle to initialize
204  * @param stack_size    size of stack for new thread, 0 for default
205  * @param start_routine main function of thread
206  * @param arg argument  for start_routine
207  * @return non-zero on success; zero otherwise
208  */
209 int
210 MHD_create_thread_ (MHD_thread_handle_ID_ *thread,
211                     size_t stack_size,
212                     MHD_THREAD_START_ROUTINE_ start_routine,
213                     void *arg);
214 
215 #ifndef MHD_USE_THREAD_NAME_
216 #define MHD_create_named_thread_(t,n,s,r,a) MHD_create_thread_ ((t),(s),(r),(a))
217 #else  /* MHD_USE_THREAD_NAME_ */
218 /**
219  * Create a named thread and set the attributes according to our options.
220  *
221  * @param thread        handle to initialize
222  * @param thread_name   name for new thread
223  * @param stack_size    size of stack for new thread, 0 for default
224  * @param start_routine main function of thread
225  * @param arg argument  for start_routine
226  * @return non-zero on success; zero otherwise
227  */
228 int
229 MHD_create_named_thread_ (MHD_thread_handle_ID_ *thread,
230                           const char *thread_name,
231                           size_t stack_size,
232                           MHD_THREAD_START_ROUTINE_ start_routine,
233                           void *arg);
234 
235 #endif /* MHD_USE_THREAD_NAME_ */
236 
237 #endif /* ! MHD_THREADS_H */
238