diff --git a/CMakeLists.txt b/CMakeLists.txt index cf47f20c..b7394664 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -440,6 +440,7 @@ endif() CHECK_INCLUDE_FILE(sys/uio.h EVENT__HAVE_SYS_UIO_H) CHECK_INCLUDE_FILES("sys/types.h;ifaddrs.h" EVENT__HAVE_IFADDRS_H) CHECK_INCLUDE_FILE(mach/mach_time.h EVENT__HAVE_MACH_MACH_TIME_H) +CHECK_INCLUDE_FILE(mach/mach.h EVENT__HAVE_MACH_MACH_H) CHECK_INCLUDE_FILE(netinet/tcp.h EVENT__HAVE_NETINET_TCP_H) CHECK_INCLUDE_FILE(sys/wait.h EVENT__HAVE_SYS_WAIT_H) CHECK_INCLUDE_FILE(sys/resource.h EVENT__HAVE_SYS_RESOURCE_H) diff --git a/configure.ac b/configure.ac index 2af10962..74fa4481 100644 --- a/configure.ac +++ b/configure.ac @@ -222,6 +222,7 @@ AC_CHECK_HEADERS([ \ fcntl.h \ ifaddrs.h \ mach/mach_time.h \ + mach/mach.h \ netdb.h \ netinet/in.h \ netinet/in6.h \ diff --git a/event-config.h.cmake b/event-config.h.cmake index 81abe3f4..1b6b561d 100644 --- a/event-config.h.cmake +++ b/event-config.h.cmake @@ -178,6 +178,9 @@ /* Define to 1 if you have the header file. */ #cmakedefine EVENT__HAVE_MACH_MACH_TIME_H 1 +/* Define to 1 if you have the header file. */ +#cmakedefine EVENT__HAVE_MACH_MACH_H 1 + /* Define to 1 if you have the header file. */ #cmakedefine EVENT__HAVE_MEMORY_H 1 diff --git a/test/regress.c b/test/regress.c index 0ebadcb9..74d7f39a 100644 --- a/test/regress.c +++ b/test/regress.c @@ -31,10 +31,6 @@ #include #endif -#ifdef EVENT__HAVE_PTHREADS -#include -#endif - #include "event2/event-config.h" #include @@ -73,6 +69,7 @@ #include "time-internal.h" #include "regress.h" +#include "regress_thread.h" #ifndef _WIN32 #include "regress.gen.h" @@ -979,7 +976,7 @@ test_fork(void) evutil_closesocket(child_pair[1]); } -#ifdef EVENT__HAVE_PTHREADS +#ifdef EVTHREAD_USE_PTHREADS_IMPLEMENTED static void* del_wait_thread(void *arg) { struct timeval tv_start, tv_end; @@ -1007,14 +1004,14 @@ static void test_del_wait(void) { struct event ev; - pthread_t thread; + THREAD_T thread; setup_test("event_del will wait: "); event_set(&ev, pair[1], EV_READ|EV_PERSIST, del_wait_cb, &ev); event_add(&ev, NULL); - pthread_create(&thread, NULL, del_wait_thread, NULL); + THREAD_START(thread, del_wait_thread, NULL); if (write(pair[0], TEST1, strlen(TEST1)+1) < 0) { tt_fail_perror("write"); @@ -1033,7 +1030,7 @@ test_del_wait(void) test_timeval_diff_eq(&tv_start, &tv_end, 270); } - pthread_join(thread, NULL); + THREAD_JOIN(thread); tt_int_op(test_ok, ==, 1); @@ -3505,8 +3502,8 @@ struct testcase_t main_testcases[] = { #ifndef _WIN32 LEGACY(fork, TT_ISOLATED), #endif -#ifdef EVENT__HAVE_PTHREADS - /** TODO: support win32 */ + +#ifdef EVTHREAD_USE_PTHREADS_IMPLEMENTED LEGACY(del_wait, TT_ISOLATED|TT_NEED_THREADS|TT_RETRIABLE), LEGACY(del_notify, TT_ISOLATED|TT_NEED_THREADS), #endif diff --git a/test/regress.h b/test/regress.h index 43cb4eaf..7b246d3c 100644 --- a/test/regress.h +++ b/test/regress.h @@ -139,6 +139,7 @@ SSL_CTX *get_ssl_ctx(void); void init_ssl(void); #endif +void thread_setup(pthread_t pthread); void * basic_test_setup(const struct testcase_t *testcase); int basic_test_cleanup(const struct testcase_t *testcase, void *ptr); diff --git a/test/regress_main.c b/test/regress_main.c index 01037137..ebca9e6b 100644 --- a/test/regress_main.c +++ b/test/regress_main.c @@ -186,6 +186,52 @@ ignore_log_cb(int s, const char *msg) { } +#if defined(__APPLE__) + +#ifdef EVENT__HAVE_MACH_MACH_H +#include +#endif +#ifdef EVENT__HAVE_MACH_MACH_TIME_H +#include +#endif +#include + +/** + * Put into the real time scheduling class for better timers latency. + * https://developer.apple.com/library/archive/technotes/tn2169/_index.html#//apple_ref/doc/uid/DTS40013172-CH1-TNTAG6000 + */ +void move_pthread_to_realtime_scheduling_class(pthread_t pthread) +{ + mach_timebase_info_data_t timebase_info; + mach_timebase_info(&timebase_info); + + const uint64_t NANOS_PER_MSEC = 1000000ULL; + double clock2abs = ((double)timebase_info.denom / (double)timebase_info.numer) * NANOS_PER_MSEC; + + thread_time_constraint_policy_data_t policy; + policy.period = 0; + policy.computation = (uint32_t)(5 * clock2abs); // 5 ms of work + policy.constraint = (uint32_t)(10 * clock2abs); + policy.preemptible = FALSE; + + int kr = thread_policy_set(pthread_mach_thread_np(pthread_self()), + THREAD_TIME_CONSTRAINT_POLICY, + (thread_policy_t)&policy, + THREAD_TIME_CONSTRAINT_POLICY_COUNT); + if (kr != KERN_SUCCESS) { + mach_error("thread_policy_set:", kr); + exit(1); + } +} + +void thread_setup(pthread_t pthread) +{ + move_pthread_to_realtime_scheduling_class(pthread); +} +#else +void thread_setup(pthread_t pthread) {} +#endif + void * basic_test_setup(const struct testcase_t *testcase) { @@ -193,6 +239,8 @@ basic_test_setup(const struct testcase_t *testcase) evutil_socket_t spair[2] = { -1, -1 }; struct basic_test_data *data = NULL; + thread_setup(pthread_self()); + #ifndef _WIN32 if (testcase->flags & TT_ENABLE_IOCP_FLAG) return (void*)TT_SKIP; diff --git a/test/regress_thread.h b/test/regress_thread.h index db0d8d19..ca79bc5c 100644 --- a/test/regress_thread.h +++ b/test/regress_thread.h @@ -27,22 +27,26 @@ #ifndef REGRESS_THREAD_H_INCLUDED_ #define REGRESS_THREAD_H_INCLUDED_ +#include "regress.h" + #ifdef EVENT__HAVE_PTHREADS #include #define THREAD_T pthread_t #define THREAD_FN void * #define THREAD_RETURN() return (NULL) -#define THREAD_START(threadvar, fn, arg) \ - pthread_create(&(threadvar), NULL, fn, arg) +#define THREAD_START(threadvar, fn, arg) do { \ + if (!pthread_create(&(threadvar), NULL, fn, arg)) \ + thread_setup(threadvar); \ +} while (0) #define THREAD_JOIN(th) pthread_join(th, NULL) #else #define THREAD_T HANDLE #define THREAD_FN unsigned __stdcall #define THREAD_RETURN() return (0) #define THREAD_START(threadvar, fn, arg) do { \ - uintptr_t threadhandle = _beginthreadex(NULL,0,fn,(arg),0,NULL); \ - (threadvar) = (HANDLE) threadhandle; \ - } while (0) + uintptr_t threadhandle = _beginthreadex(NULL,0,fn,(arg),0,NULL); \ + (threadvar) = (HANDLE) threadhandle; \ +} while (0) #define THREAD_JOIN(th) WaitForSingleObject(th, INFINITE) #endif