Added ability to use native W32 threads, added --with-threads=LIB configure parameter

This commit is contained in:
Evgeny Grin (Karlson2k)
2014-04-08 14:46:06 +00:00
parent 1c5f53ac93
commit 2bffe00f07
13 changed files with 234 additions and 58 deletions
+4
View File
@@ -1,3 +1,7 @@
Tue Apr 08 15:35:44 CET 2014
Added support for W32 native threads.
Added --with-threads=LIB configure parameter. -EG
Mon Apr 7 13:25:30 CEST 2014
Add MHD_OPTION_HTTPS_MEM_DHPARAMS to allow applications
to enable PFS. -HB/CG
+111 -29
View File
@@ -81,19 +81,36 @@ AC_SUBST([PACKAGE_VERSION_MINOR])
AC_SUBST([PACKAGE_VERSION_SUBMINOR])
AC_CONFIG_FILES([src/microhttpd/microhttpd_dll_res.rc])
AX_PTHREAD(,[AC_MSG_ERROR([[Compiling libmicrohttpd requires pthread support]])])
CC="$PTHREAD_CC"
MHD_LIB_CPPFLAGS=""
MHD_LIB_CFLAGS=""
MHD_LIB_LDFLAGS=""
MHD_LIBDEPS=""
# set GCC options
# use '-fno-strict-aliasing', but only if the compiler can take it
AX_APPEND_COMPILE_FLAGS([[-fno-strict-aliasing]])
AC_ARG_WITH([threads],
[AC_HELP_STRING([--with-threads=LIB],[choose threading library (posix, w32, auto) [auto]])],
[], [with_threads='auto'])
test "x$with_threads" = "xwin32" && with_threads='w32'
test "x$with_threads" = "xpthreads" && with_threads='posix'
AC_C_BIGENDIAN
AC_CHECK_PROG([HAVE_CURL_BINARY],[curl],[yes],[no])
AM_CONDITIONAL([HAVE_CURL_BINARY],[test "x$HAVE_CURL_BINARY" = "xyes"])
AC_CHECK_PROG([HAVE_MAKEINFO_BINARY],[makeinfo],[yes],[no])
AM_CONDITIONAL([HAVE_MAKEINFO_BINARY],[test "x$HAVE_MAKEINFO_BINARY" = "xyes"])
# Check for posix threads support
AX_PTHREAD([HAVE_POSIX_THREADS='yes'],[HAVE_POSIX_THREADS='no'])
AM_CONDITIONAL([HAVE_POSIX_THREADS],[test "x$HAVE_POSIX_THREADS" = "xyes"])
# Simple check for W32 threads support
AC_CHECK_HEADER([windows.h],
[
AC_MSG_CHECKING([for CreateThread()])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([#include <windows.h>], [ HANDLE h = CreateThread(NULL, 0, NULL, NULL, 0, NULL);])],
[
AC_MSG_RESULT([yes])
HAVE_W32_THREADS='yes'
],
[
AC_MSG_RESULT([no])
HAVE_W32_THREADS='no'
])
],
[HAVE_W32_THREADS='no'])
# for pkg-config
MHD_LIBDEPS=""
@@ -156,7 +173,7 @@ netbsd*)
AC_DEFINE_UNQUOTED(OS390,1,[This is a OS/390 system])
;;
*)
AC_MSG_RESULT(Unrecognised OS $host_os)
AC_MSG_WARN([Unrecognised OS $host_os])
AC_DEFINE_UNQUOTED(OTHEROS,1,[Some strange OS])
# You might want to find out if your OS supports shutdown on listen sockets,
# and extend the switch statement; if we do not have 'HAVE_LISTEN_SHUTDOWN',
@@ -165,6 +182,57 @@ netbsd*)
;;
esac
if test "x$with_threads" = "xposix"; then
# forced posix threads
if test "x$HAVE_POSIX_THREADS" = "xyes"; then
USE_THREADS='posix'
else
if test "x$HAVE_W32_THREADS" = "xyes"; then
AC_MSG_ERROR([[Posix threads are not available. Try to configure --with-threads=auto]])
else
AC_MSG_ERROR([[Posix threads are not available]])
fi
fi
elif test "x$with_threads" = "xw32"; then
# forced w32 threads
if test "x$HAVE_W32_THREADS" = "xyes"; then
USE_THREADS='w32'
else
if test "x$HAVE_POSIX_THREADS" = "xyes"; then
AC_MSG_ERROR([[W32 threads are not available. Try to configure --with-threads=auto]])
else
AC_MSG_ERROR([[W32 threads are not available]])
fi
fi
else
# automatic threads lib selection
if test "x$HAVE_POSIX_THREADS" = "xyes" && test "x$HAVE_W32_THREADS" = "xyes"; then
if test "x$os_is_native_w32" = "xyes"; then
USE_THREADS='w32'
else
USE_THREADS='posix'
fi
elif test "x$HAVE_POSIX_THREADS" = "xyes"; then
USE_THREADS='posix'
elif test "x$HAVE_W32_THREADS" = "xyes"; then
USE_THREADS='w32'
else
AC_MSG_ERROR([[No threading lib is available. Cosider installing pthreads]])
fi
fi
if test "x$USE_THREADS" = "xposix"; then
CC="$PTHREAD_CC"
AC_DEFINE([MHD_USE_POSIX_THREADS],[1],[define to use pthreads])
MHD_LIB_CFLAGS="$MHD_LIB_CFLAGS $PTHREAD_CFLAGS"
MHD_LIBDEPS="$PTHREAD_LIBS $MHD_LIBDEPS"
elif test "x$USE_THREADS" = "xw32"; then
AC_DEFINE([MHD_USE_W32_THREADS],[1],[define to use W32 threads])
fi
AM_CONDITIONAL([USE_POSIX_THREADS], [test "x$USE_THREADS" = "xposix"])
AM_CONDITIONAL([USE_W32_THREADS], [test "x$USE_THREADS" = "xw32"])
AM_CONDITIONAL(HAVE_W32, [test "x$os_is_native_w32" = "xyes"])
w32_shared_lib_exp=no
if test "x$enable_shared" = "xyes" && test "x$os_is_native_w32" = "xyes"; then
@@ -177,6 +245,17 @@ if test "x$enable_shared" = "xyes" && test "x$os_is_native_w32" = "xyes"; then
fi
AM_CONDITIONAL(W32_SHARED_LIB_EXP, [test "x$w32_shared_lib_exp" = "xyes"])
AM_CONDITIONAL(USE_MS_LIB_TOOL, [test "x$ac_cv_use_ms_lib_tool" = "xyes"])
# set GCC options
# use '-fno-strict-aliasing', but only if the compiler can take it
AX_APPEND_COMPILE_FLAGS([[-fno-strict-aliasing]])
AC_C_BIGENDIAN
AC_CHECK_PROG([HAVE_CURL_BINARY],[curl],[yes],[no])
AM_CONDITIONAL([HAVE_CURL_BINARY],[test "x$HAVE_CURL_BINARY" = "xyes"])
AC_CHECK_PROG([HAVE_MAKEINFO_BINARY],[makeinfo],[yes],[no])
AM_CONDITIONAL([HAVE_MAKEINFO_BINARY],[test "x$HAVE_MAKEINFO_BINARY" = "xyes"])
AM_CONDITIONAL(W32_STATIC_LIB, [test "x$os_is_native_w32" = "xyes" && test "x$enable_static" = "xyes"])
@@ -212,19 +291,21 @@ if test "$enable_epoll" != "no"; then
fi
fi
SAVE_LIBS="$LIBS"
SAVE_CFLAGS="$CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
# Check for pthread_setname_np()
AC_MSG_CHECKING([[for pthread_setname_np]])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[#include <pthread.h>]], [[ pthread_setname_np(pthread_self(), "name")]])],
[AC_DEFINE([[HAVE_PTHREAD_SETNAME_NP]], [[1]], [Define if you have pthread_setname_np function.])
AC_MSG_RESULT([[yes]])],
[AC_MSG_RESULT([[no]])] )
LIBS="$SAVE_LIBS"
CFLAGS="$SAVE_CFLAGS"
if test "x$HAVE_POSIX_THREADS" = "xyes"; then
# Check for pthread_setname_np()
SAVE_LIBS="$LIBS"
SAVE_CFLAGS="$CFLAGS"
LIBS="$PTHREAD_LIBS $LIBS"
CFLAGS="$CFLAGS $PTHREAD_CFLAGS"
AC_MSG_CHECKING([[for pthread_setname_np]])
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[#include <pthread.h>]], [[ pthread_setname_np(pthread_self(), "name")]])],
[AC_DEFINE([[HAVE_PTHREAD_SETNAME_NP]], [[1]], [Define if you have pthread_setname_np function.])
AC_MSG_RESULT([[yes]])],
[AC_MSG_RESULT([[no]])] )
LIBS="$SAVE_LIBS"
CFLAGS="$SAVE_CFLAGS"
fi
# Check for headers that are ALWAYS required
AC_CHECK_HEADERS([fcntl.h math.h errno.h limits.h stdio.h locale.h sys/stat.h sys/types.h pthread.h],,AC_MSG_ERROR([Compiling libmicrohttpd requires standard UNIX headers files]))
@@ -599,10 +680,10 @@ if test "x$enable_https" != "xno"
then
AS_IF([test "x$have_gnutls" = "xyes" && test "x$have_gcrypt" = "xyes"], [
AC_DEFINE([HTTPS_SUPPORT],[1],[include HTTPS support])
MHD_LIB_CPPFLAGS="$GNUTLS_CPPFLAGS $LIBGCRYPT_CFLAGS"
MHD_LIB_CFLAGS="$GNUTLS_CFLAGS $LIBGCRYPT_CFLAGS"
MHD_LIB_LDFLAGS="$GNUTLS_LDFLAGS"
MHD_LIBDEPS="$GNUTLS_LIBS $LIBGCRYPT_LIBS"
MHD_LIB_CPPFLAGS="$MHD_LIB_CPPFLAGS $GNUTLS_CPPFLAGS $LIBGCRYPT_CFLAGS"
MHD_LIB_CFLAGS="$MHD_LIB_CFLAGS $GNUTLS_CFLAGS $LIBGCRYPT_CFLAGS"
MHD_LIB_LDFLAGS="$MHD_LIB_LDFLAGS $GNUTLS_LDFLAGS"
MHD_LIBDEPS="$GNUTLS_LIBS $LIBGCRYPT_LIBS $MHD_LIBDEPS"
enable_https=yes
MSG_HTTPS="yes (using libgnutls and libgcrypt)"
], [
@@ -715,6 +796,7 @@ fi
AC_MSG_NOTICE([Configuration Summary:
Operating System: ${host_os}
Threading lib: ${USE_THREADS}
libcurl (testing): ${MSG_CURL}
Target directory: ${prefix}
Messages: ${enable_messages}
+2
View File
@@ -74,9 +74,11 @@
#include <fcntl.h>
#include <signal.h>
#include <stddef.h>
#ifdef MHD_USE_POSIX_THREADS
#undef HAVE_CONFIG_H
#include <pthread.h>
#define HAVE_CONFIG_H 1
#endif // MHD_USE_POSIX_THREADS
/* different OSes have fd_set in
a broad range of header files;
+36 -2
View File
@@ -139,11 +139,45 @@
#define MHD_random_() MHD_W32_random_()
#endif
#if defined(_WIN32) && !defined(__CYGWIN__)
#if defined(MHD_USE_POSIX_THREADS)
typedef pthread_t MHD_thread_handle_;
#elif defined(MHD_USE_W32_THREADS)
#include <windows.h>
typedef HANDLE MHD_thread_handle_;
#else
#error "No threading API is available."
#endif
#if defined(MHD_USE_POSIX_THREADS)
#define MHD_THRD_RTRN_TYPE_ void*
#define MHD_THRD_CALL_SPEC_
#elif defined(MHD_USE_W32_THREADS)
#define MHD_THRD_RTRN_TYPE_ DWORD
#define MHD_THRD_CALL_SPEC_ WINAPI
#endif
#if defined(MHD_USE_POSIX_THREADS)
/**
* Wait until specified thread is ended
* @param thread ID to watch
* @return zero on success, nonzero on failure
*/
#define MHD_join_thread_(thread) pthread_join((thread), NULL)
#elif defined(MHD_USE_W32_THREADS)
/**
* Wait until specified thread is ended
* Close thread handle on success
* @param thread handle to watch
* @return zero on success, nonzero on failure
*/
#define MHD_join_thread_(thread) (WAIT_OBJECT_0 == WaitForSingleObject((thread), INFINITE) ? (CloseHandle((thread)), 0) : 1 )
#endif
#if defined(MHD_USE_W32_THREADS)
#define MHD_W32_MUTEX_ 1
#include <windows.h>
typedef CRITICAL_SECTION MHD_mutex_;
#elif defined(HAVE_PTHREAD_H)
#elif defined(HAVE_PTHREAD_H) && defined(MHD_USE_POSIX_THREADS)
#define MHD_PTHREAD_MUTEX_ 1
typedef pthread_mutex_t MHD_mutex_;
#else
+3
View File
@@ -146,6 +146,9 @@ extern "C"
#ifndef ENODATA
#define ENODATA (MHDW32ERRBASE+35)
#endif
#ifndef ETIMEDOUT
#define ETIMEDOUT (MHDW32ERRBASE+36)
#endif
/**
* Return errno equivalent of last winsock error
+2 -2
View File
@@ -66,13 +66,13 @@ libmicrohttpd_la_CPPFLAGS = \
$(AM_CPPFLAGS) $(MHD_LIB_CPPFLAGS) \
-DBUILDING_MHD_LIB=1
libmicrohttpd_la_CFLAGS = \
$(PTHREAD_CFLAGS) $(AM_CFLAGS) $(MHD_LIB_CFLAGS)
$(AM_CFLAGS) $(MHD_LIB_CFLAGS)
libmicrohttpd_la_LDFLAGS = \
$(MHD_LIB_LDFLAGS) \
$(W32_MHD_LIB_LDFLAGS) \
-version-info @LIB_VERSION_CURRENT@:@LIB_VERSION_REVISION@:@LIB_VERSION_AGE@
libmicrohttpd_la_LIBADD = \
$(MHD_W32_LIB) $(PTHREAD_LIBS) $(MHD_LIBDEPS)
$(MHD_W32_LIB) $(MHD_LIBDEPS)
if HAVE_W32
MHD_DLL_RES_SRC = microhttpd_dll_res.rc
+58 -16
View File
@@ -740,9 +740,9 @@ MHD_get_fdset2 (struct MHD_Daemon *daemon,
* connection when #MHD_USE_THREAD_PER_CONNECTION is set.
*
* @param data the 'struct MHD_Connection' this thread will handle
* @return always NULL
* @return always 0
*/
static void *
static MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_
MHD_handle_connection (void *data)
{
struct MHD_Connection *con = data;
@@ -920,7 +920,7 @@ exit:
MHD_destroy_response (con->response);
con->response = NULL;
}
return NULL;
return (MHD_THRD_RTRN_TYPE_)0;
}
@@ -1039,7 +1039,7 @@ send_param_adapter (struct MHD_Connection *connection,
* @param cls closure argument for the function
* @return termination code from the thread
*/
typedef void *(*ThreadStartRoutine)(void *cls);
typedef MHD_THRD_RTRN_TYPE_ (MHD_THRD_CALL_SPEC_ *ThreadStartRoutine)(void *cls);
/**
@@ -1052,11 +1052,12 @@ typedef void *(*ThreadStartRoutine)(void *cls);
* @return 0 on success
*/
static int
create_thread (pthread_t *thread,
create_thread (MHD_thread_handle_ *thread,
const struct MHD_Daemon *daemon,
ThreadStartRoutine start_routine,
void *arg)
{
#if defined(MHD_USE_POSIX_THREADS)
pthread_attr_t attr;
pthread_attr_t *pattr;
int ret;
@@ -1091,6 +1092,11 @@ create_thread (pthread_t *thread,
#endif
errno = EINVAL;
return ret;
#elif defined(MHD_USE_W32_THREADS)
*thread = CreateThread(NULL, daemon->thread_stack_size, start_routine,
arg, 0, NULL);
return (NULL != (*thread)) ? 0 : 1;
#endif
}
@@ -1858,7 +1864,7 @@ MHD_cleanup_connections (struct MHD_Daemon *daemon)
if ( (0 != (daemon->options & MHD_USE_THREAD_PER_CONNECTION)) &&
(MHD_NO == pos->thread_joined) )
{
if (0 != pthread_join (pos->pid, NULL))
if (0 != MHD_join_thread_ (pos->pid))
{
MHD_PANIC ("Failed to join a thread\n");
}
@@ -2693,9 +2699,9 @@ MHD_run (struct MHD_Daemon *daemon)
* is explicitly shut down.
*
* @param cls 'struct MHD_Deamon' to run select loop in a thread for
* @return always NULL (on shutdown)
* @return always 0 (on shutdown)
*/
static void *
static MHD_THRD_RTRN_TYPE_ MHD_THRD_CALL_SPEC_
MHD_select_thread (void *cls)
{
struct MHD_Daemon *daemon = cls;
@@ -2712,7 +2718,7 @@ MHD_select_thread (void *cls)
MHD_select (daemon, MHD_YES);
MHD_cleanup_connections (daemon);
}
return NULL;
return (MHD_THRD_RTRN_TYPE_)0;
}
@@ -4012,7 +4018,7 @@ close_all_connections (struct MHD_Daemon *daemon)
{
while (NULL != (pos = daemon->connections_head))
{
if (0 != pthread_join (pos->pid, NULL))
if (0 != MHD_join_thread_ (pos->pid))
MHD_PANIC ("Failed to join a thread\n");
pos->thread_joined = MHD_YES;
}
@@ -4123,7 +4129,7 @@ MHD_stop_daemon (struct MHD_Daemon *daemon)
if (1 != MHD_pipe_write_ (daemon->worker_pool[i].wpipe[1], "e", 1))
MHD_PANIC ("failed to signal shutdown via pipe");
}
if (0 != pthread_join (daemon->worker_pool[i].pid, NULL))
if (0 != MHD_join_thread_ (daemon->worker_pool[i].pid))
MHD_PANIC ("Failed to join a thread\n");
close_all_connections (&daemon->worker_pool[i]);
(void) MHD_mutex_destroy_ (&daemon->worker_pool[i].cleanup_connection_mutex);
@@ -4152,7 +4158,7 @@ MHD_stop_daemon (struct MHD_Daemon *daemon)
((0 != (daemon->options & MHD_USE_SELECT_INTERNALLY))
&& (0 == daemon->worker_pool_size)))
{
if (0 != pthread_join (daemon->pid, NULL))
if (0 != MHD_join_thread_ (daemon->pid))
{
MHD_PANIC ("Failed to join a thread\n");
}
@@ -4380,11 +4386,42 @@ MHD_is_feature_supported(enum MHD_FEATURE feature)
#define FUNC_DESTRUCTOR(f) _MHD_EXTERN void f
#endif // __GNUC__
#if HTTPS_SUPPORT
#if GCRYPT_VERSION_NUMBER < 0x010600
#if HTTPS_SUPPORT && GCRYPT_VERSION_NUMBER < 0x010600
#if defined(MHD_USE_POSIX_THREADS)
GCRY_THREAD_OPTION_PTHREAD_IMPL;
#endif
#endif
#elif defined(MHD_W32_MUTEX_)
static int gcry_w32_mutex_init (void **ppmtx)
{
*ppmtx = malloc (sizeof (MHD_mutex_));
if (NULL == *ppmtx)
return ENOMEM;
if (MHD_YES != MHD_mutex_create_ ((MHD_mutex_*)*ppmtx))
{
free (*ppmtx);
*ppmtx = NULL;
return EPERM;
}
return 0;
}
static int gcry_w32_mutex_destroy (void **ppmtx)
{ int res = (MHD_YES == MHD_mutex_destroy_ ((MHD_mutex_*)*ppmtx)) ? 0 : 1;
free (*ppmtx); return res; }
static int gcry_w32_mutex_lock (void **ppmtx)
{ return (MHD_YES == MHD_mutex_lock_ ((MHD_mutex_*)*ppmtx)) ? 0 : 1; }
static int gcry_w32_mutex_unlock (void **ppmtx)
{ return (MHD_YES == MHD_mutex_unlock_ ((MHD_mutex_*)*ppmtx)) ? 0 : 1; }
static struct gcry_thread_cbs gcry_threads_w32 = {
(GCRY_THREAD_OPTION_USER | (GCRY_THREAD_OPTION_VERSION << 8)),
NULL, gcry_w32_mutex_init, gcry_w32_mutex_destroy,
gcry_w32_mutex_lock, gcry_w32_mutex_unlock,
NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL };
#endif // defined(MHD_W32_MUTEX_)
#endif // HTTPS_SUPPORT && GCRYPT_VERSION_NUMBER < 0x010600
/**
@@ -4405,8 +4442,13 @@ FUNC_CONSTRUCTOR (MHD_init) ()
#endif
#if HTTPS_SUPPORT
#if GCRYPT_VERSION_NUMBER < 0x010600
#if defined(MHD_USE_POSIX_THREADS)
if (0 != gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_pthread))
MHD_PANIC ("Failed to initialise multithreading in libgcrypt\n");
#elif defined(MHD_W32_MUTEX_)
if (0 != gcry_control (GCRYCTL_SET_THREAD_CBS, &gcry_threads_w32))
MHD_PANIC ("Failed to initialise multithreading in libgcrypt\n");
#endif // defined(MHD_W32_MUTEX_)
gcry_check_version (NULL);
#else
if (NULL == gcry_check_version ("1.6.0"))
+4 -4
View File
@@ -637,10 +637,10 @@ struct MHD_Connection
struct sockaddr *addr;
/**
* Thread for this connection (if we are using
* Thread handle for this connection (if we are using
* one thread per connection).
*/
pthread_t pid;
MHD_thread_handle_ pid;
/**
* Size of read_buffer (in bytes). This value indicates
@@ -1070,9 +1070,9 @@ struct MHD_Daemon
unsigned int worker_pool_size;
/**
* PID of the select thread (if we have internal select)
* The select thread handle (if we have internal select)
*/
pthread_t pid;
MHD_thread_handle_ pid;
/**
* Mutex for per-IP connection counts.
+4 -1
View File
@@ -25,7 +25,6 @@ endif
if HAVE_CURL
check_PROGRAMS = \
test_start_stop \
test_quiesce \
test_get \
test_get_sendfile \
test_urlparse \
@@ -49,6 +48,10 @@ check_PROGRAMS = \
$(CURL_FORK_TEST) \
perf_get $(PERF_GET_CONCURRENT)
if HAVE_POSIX_THREADS
check_PROGRAMS += \
test_quiesce
endif
if HAVE_POSTPROCESSOR
check_PROGRAMS += \
+7 -4
View File
@@ -8,6 +8,11 @@ if HAVE_GNUTLS_SNI
TEST_HTTPS_SNI = test_https_sni
endif
if HAVE_POSIX_THREADS
HTTPS_PARALLEL_TESTS = test_https_get_parallel \
test_https_get_parallel_threads
endif
CPU_COUNT_DEF = -DCPU_COUNT=$(CPU_COUNT)
AM_CPPFLAGS = \
@@ -23,8 +28,7 @@ check_PROGRAMS = \
test_https_get \
$(TEST_HTTPS_SNI) \
test_https_get_select \
test_https_get_parallel \
test_https_get_parallel_threads \
$(HTTPS_PARALLEL_TESTS) \
test_https_session_info \
test_https_time_out \
test_empty_response
@@ -38,8 +42,7 @@ TESTS = \
test_https_get \
$(TEST_HTTPS_SNI) \
test_https_get_select \
test_https_get_parallel \
test_https_get_parallel_threads \
$(HTTPS_PARALLEL_TESTS) \
test_https_session_info \
test_https_time_out \
test_tls_authentication \
@@ -30,6 +30,7 @@
#include <sys/stat.h>
#include <limits.h>
#include <curl/curl.h>
#include <pthread.h>
#include <gcrypt.h>
#include "tls_test_common.h"
@@ -32,6 +32,7 @@
#include <sys/stat.h>
#include <limits.h>
#include <curl/curl.h>
#include <pthread.h>
#include <gcrypt.h>
#include "tls_test_common.h"
+1
View File
@@ -33,6 +33,7 @@
#include <string.h>
#include <time.h>
#include <sys/types.h>
#include <pthread.h>
#ifndef WINDOWS
#include <unistd.h>