mirror of
https://github.com/wolfcw/libfaketime.git
synced 2026-05-17 08:36:28 +03:00
Merge pull request #138 from mliertzer/fake_pthread
Implement fix for pthread_cond_timedwait
This commit is contained in:
30
src/Makefile
30
src/Makefile
@@ -9,12 +9,9 @@
|
||||
# NO_ATFILE
|
||||
# - Disables support for the fstatat() group of functions
|
||||
#
|
||||
# PTHREAD
|
||||
# - Define this to enable multithreading support.
|
||||
#
|
||||
# PTHREAD_SINGLETHREADED_TIME
|
||||
# - Define this if you want to single-thread time() ... there ARE
|
||||
# possibile caching side-effects in a multithreaded environment
|
||||
# possible caching side-effects in a multithreaded environment
|
||||
# without this, but the performance impact may require you to
|
||||
# try it unsynchronized.
|
||||
#
|
||||
@@ -24,17 +21,20 @@
|
||||
# that make use of low-level system calls, such as Java Virtual
|
||||
# Machines.
|
||||
#
|
||||
# FAKE_SLEEP
|
||||
# - Also intercept sleep(), nanosleep(), usleep(), alarm(), [p]poll()
|
||||
# FAKE_SLEEP
|
||||
# - Also intercept sleep(), nanosleep(), usleep(), alarm(), [p]poll()
|
||||
#
|
||||
# FAKE_TIMERS
|
||||
# - Also intercept timer_settime() and timer_gettime()
|
||||
# FAKE_TIMERS
|
||||
# - Also intercept timer_settime() and timer_gettime()
|
||||
#
|
||||
# MULTI_ARCH
|
||||
# - If MULTI_ARCH is set, the faketime wrapper program will put a literal
|
||||
# $LIB into the LD_PRELOAD environment variable it creates, which makes
|
||||
# ld automatically choose the correct library version to use for the
|
||||
# target binary. Use for Linux platforms with Multi-Arch support only!
|
||||
# FAKE_PTHREAD
|
||||
# - Intercept pthread_cond_timedwait
|
||||
#
|
||||
# MULTI_ARCH
|
||||
# - If MULTI_ARCH is set, the faketime wrapper program will put a literal
|
||||
# $LIB into the LD_PRELOAD environment variable it creates, which makes
|
||||
# ld automatically choose the correct library version to use for the
|
||||
# target binary. Use for Linux platforms with Multi-Arch support only!
|
||||
#
|
||||
# * Compilation addition: second libMT target added for building the pthread-
|
||||
# enabled library as a separate library
|
||||
@@ -62,7 +62,7 @@ PREFIX ?= /usr/local
|
||||
LIBDIRNAME ?= /lib/faketime
|
||||
PLATFORM ?=$(shell uname)
|
||||
|
||||
CFLAGS += -std=gnu99 -Wall -Wextra -Werror -Wno-nonnull-compare -DFAKE_STAT -DFAKE_SLEEP -DFAKE_TIMERS -DFAKE_INTERNAL_CALLS -fPIC -DPREFIX='"'$(PREFIX)'"' -DLIBDIRNAME='"'$(LIBDIRNAME)'"'
|
||||
CFLAGS += -std=gnu99 -Wall -Wextra -Werror -Wno-nonnull-compare -DFAKE_PTHREAD -DFAKE_STAT -DFAKE_SLEEP -DFAKE_TIMERS -DFAKE_INTERNAL_CALLS -fPIC -DPREFIX='"'$(PREFIX)'"' -DLIBDIRNAME='"'$(LIBDIRNAME)'"'
|
||||
ifeq ($(PLATFORM),SunOS)
|
||||
CFLAGS += -D__EXTENSIONS__ -D_XOPEN_SOURCE=600
|
||||
endif
|
||||
@@ -86,7 +86,7 @@ LIBS = libfaketime.so.${SONAME} libfaketimeMT.so.${SONAME}
|
||||
|
||||
all: ${LIBS} ${BINS}
|
||||
|
||||
libfaketimeMT.o: EXTRA_FLAGS := -DPTHREAD -DPTHREAD_SINGLETHREADED_TIME
|
||||
libfaketimeMT.o: EXTRA_FLAGS := -DPTHREAD_SINGLETHREADED_TIME
|
||||
|
||||
${LIBS_OBJ}: libfaketime.c
|
||||
${CC} -o $@ -c ${CFLAGS} ${EXTRA_FLAGS} $<
|
||||
|
||||
@@ -41,11 +41,14 @@
|
||||
#include <netinet/in.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "uthash.h"
|
||||
|
||||
#include "time_ops.h"
|
||||
#include "faketime_common.h"
|
||||
|
||||
|
||||
/* pthread-handling contributed by David North, TDI in version 0.7 */
|
||||
#ifdef PTHREAD
|
||||
#if defined PTHREAD_SINGLETHREADED_TIME || defined FAKE_PTHREAD
|
||||
#include <pthread.h>
|
||||
#endif
|
||||
|
||||
@@ -140,6 +143,13 @@ static int (*real___ftime) (struct timeb *);
|
||||
static int (*real___gettimeofday) (struct timeval *, void *);
|
||||
static int (*real___clock_gettime) (clockid_t clk_id, struct timespec *tp);
|
||||
#endif
|
||||
#ifdef FAKE_PTHREAD
|
||||
static int (*real_pthread_cond_timedwait_225) (pthread_cond_t *, pthread_mutex_t*, struct timespec *);
|
||||
static int (*real_pthread_cond_timedwait_232) (pthread_cond_t *, pthread_mutex_t*, struct timespec *);
|
||||
static int (*real_pthread_cond_init_232) (pthread_cond_t *restrict, const pthread_condattr_t *restrict);
|
||||
static int (*real_pthread_cond_destroy_232) (pthread_cond_t *);
|
||||
#endif
|
||||
|
||||
#ifndef __APPLEOSX__
|
||||
#ifdef FAKE_TIMERS
|
||||
static int (*real_timer_settime_22) (int timerid, int flags, const struct itimerspec *new_value,
|
||||
@@ -255,8 +265,8 @@ enum ft_mode_t {FT_FREEZE, FT_START_AT, FT_NOOP} ft_mode = FT_FREEZE;
|
||||
/* Time to fake is not provided through FAKETIME env. var. */
|
||||
static bool parse_config_file = true;
|
||||
|
||||
void ft_cleanup (void) __attribute__ ((destructor));
|
||||
void ftpl_init (void) __attribute__ ((constructor));
|
||||
static void ft_cleanup (void) __attribute__ ((destructor));
|
||||
static void ftpl_init (void) __attribute__ ((constructor));
|
||||
|
||||
|
||||
/*
|
||||
@@ -299,7 +309,7 @@ static void ft_shm_init (void)
|
||||
}
|
||||
}
|
||||
|
||||
void ft_cleanup (void)
|
||||
static void ft_cleanup (void)
|
||||
{
|
||||
/* detach from shared memory */
|
||||
if (ft_shared != NULL)
|
||||
@@ -1128,7 +1138,7 @@ typedef union {
|
||||
/*
|
||||
* Faketime's function implementation's compatibility mode
|
||||
*/
|
||||
typedef enum {FT_COMPAT_GLIBC_2_2, FT_COMPAT_GLIBC_2_3_3} ft_lib_compat;
|
||||
typedef enum {FT_COMPAT_GLIBC_2_2, FT_COMPAT_GLIBC_2_3_3} ft_lib_compat_timer;
|
||||
|
||||
|
||||
/*
|
||||
@@ -1138,7 +1148,7 @@ typedef enum {FT_COMPAT_GLIBC_2_2, FT_COMPAT_GLIBC_2_3_3} ft_lib_compat;
|
||||
static int
|
||||
timer_settime_common(timer_t_or_int timerid, int flags,
|
||||
const struct itimerspec *new_value,
|
||||
struct itimerspec *old_value, ft_lib_compat compat)
|
||||
struct itimerspec *old_value, ft_lib_compat_timer compat)
|
||||
{
|
||||
int result;
|
||||
struct itimerspec new_real;
|
||||
@@ -1293,7 +1303,7 @@ int timer_settime_233(timer_t timerid, int flags,
|
||||
* Faked timer_gettime()
|
||||
* Does not affect timer speed when stepping clock with each time() call.
|
||||
*/
|
||||
int timer_gettime_common(timer_t_or_int timerid, struct itimerspec *curr_value, ft_lib_compat compat)
|
||||
int timer_gettime_common(timer_t_or_int timerid, struct itimerspec *curr_value, ft_lib_compat_timer compat)
|
||||
{
|
||||
int result;
|
||||
|
||||
@@ -1521,7 +1531,14 @@ int clock_gettime(clockid_t clk_id, struct timespec *tp)
|
||||
if (result == -1) return result; /* original function failed */
|
||||
|
||||
/* pass the real current time to our faking version, overwriting it */
|
||||
if (fake_monotonic_clock || clk_id != CLOCK_MONOTONIC)
|
||||
if (fake_monotonic_clock || (clk_id != CLOCK_MONOTONIC && clk_id != CLOCK_MONOTONIC_RAW
|
||||
#ifdef CLOCK_MONOTONIC_COARSE
|
||||
&& clk_id != CLOCK_MONOTONIC_COARSE
|
||||
#endif
|
||||
#ifdef CLOCK_BOOTTIME
|
||||
&& clk_id != CLOCK_BOOTTIME
|
||||
#endif
|
||||
))
|
||||
{
|
||||
result = fake_clock_gettime(clk_id, tp);
|
||||
}
|
||||
@@ -1636,7 +1653,7 @@ parse_modifiers:
|
||||
* =======================================================================
|
||||
*/
|
||||
|
||||
void ftpl_init(void)
|
||||
static void ftpl_init(void)
|
||||
{
|
||||
char *tmp_env;
|
||||
bool dont_fake_final;
|
||||
@@ -1674,6 +1691,26 @@ void ftpl_init(void)
|
||||
real___gettimeofday = dlsym(RTLD_NEXT, "__gettimeofday");
|
||||
real___clock_gettime = dlsym(RTLD_NEXT, "__clock_gettime");
|
||||
#endif
|
||||
#ifdef FAKE_PTHREAD
|
||||
real_pthread_cond_timedwait_225 = dlvsym(RTLD_NEXT, "pthread_cond_timedwait", "GLIBC_2.2.5");
|
||||
|
||||
real_pthread_cond_timedwait_232 = dlvsym(RTLD_NEXT, "pthread_cond_timedwait", "GLIBC_2.3.2");
|
||||
real_pthread_cond_init_232 = dlvsym(RTLD_NEXT, "pthread_cond_init", "GLIBC_2.3.2");
|
||||
real_pthread_cond_destroy_232 = dlvsym(RTLD_NEXT, "pthread_cond_destroy", "GLIBC_2.3.2");
|
||||
|
||||
if (NULL == real_pthread_cond_timedwait_232)
|
||||
{
|
||||
real_pthread_cond_timedwait_232 = dlsym(RTLD_NEXT, "pthread_cond_timedwait");
|
||||
}
|
||||
if (NULL == real_pthread_cond_init_232)
|
||||
{
|
||||
real_pthread_cond_init_232 = dlsym(RTLD_NEXT, "pthread_cond_init");
|
||||
}
|
||||
if (NULL == real_pthread_cond_destroy_232)
|
||||
{
|
||||
real_pthread_cond_destroy_232 = dlsym(RTLD_NEXT, "pthread_cond_destroy");
|
||||
}
|
||||
#endif
|
||||
#ifdef __APPLEOSX__
|
||||
real_clock_get_time = dlsym(RTLD_NEXT, "clock_get_time");
|
||||
real_clock_gettime = apple_clock_gettime;
|
||||
@@ -2327,7 +2364,15 @@ int __clock_gettime(clockid_t clk_id, struct timespec *tp)
|
||||
if (result == -1) return result; /* original function failed */
|
||||
|
||||
/* pass the real current time to our faking version, overwriting it */
|
||||
if (fake_monotonic_clock || clk_id != CLOCK_MONOTONIC)
|
||||
if (fake_monotonic_clock || (clk_id != CLOCK_MONOTONIC && clk_id != CLOCK_MONOTONIC_RAW
|
||||
#ifdef CLOCK_MONOTONIC_COARSE
|
||||
&& clk_id != CLOCK_MONOTONIC_COARSE
|
||||
#endif
|
||||
#ifdef CLOCK_BOOTTIME
|
||||
&& clk_id != CLOCK_BOOTTIME
|
||||
#endif
|
||||
))
|
||||
|
||||
{
|
||||
result = fake_clock_gettime(clk_id, tp);
|
||||
}
|
||||
@@ -2394,6 +2439,150 @@ int __ftime(struct timeb *tb)
|
||||
|
||||
#endif
|
||||
|
||||
/*
|
||||
* =======================================================================
|
||||
* Faked pthread_cond_timedwait === FAKE(pthread)
|
||||
* =======================================================================
|
||||
*/
|
||||
|
||||
/* pthread_cond_timedwait
|
||||
|
||||
The specified absolute time in pthread_cond_timedwait is directly
|
||||
passed to the kernel via the futex syscall. The kernel, however,
|
||||
does not know about the fake time. In 99.9% of cases, the time
|
||||
until this function should wait is calculated by an application
|
||||
relatively to the current time, which has been faked in the
|
||||
application. Hence, we should convert the waiting time back to real
|
||||
time.
|
||||
|
||||
pthread_cond_timedwait in GLIBC_2_2_5 only supports
|
||||
CLOCK_REALTIME. Since the init and destroy functions are not
|
||||
redefined for GLIBC_2_2_5, a corresponding cond will never be
|
||||
added to monotonic_conds and hence the correct branch will
|
||||
always be taken.
|
||||
*/
|
||||
|
||||
|
||||
#ifdef FAKE_PTHREAD
|
||||
|
||||
typedef enum {FT_COMPAT_GLIBC_2_2_5, FT_COMPAT_GLIBC_2_3_2} ft_lib_compat_pthread;
|
||||
|
||||
struct pthread_cond_monotonic {
|
||||
pthread_cond_t *ptr;
|
||||
UT_hash_handle hh;
|
||||
};
|
||||
|
||||
static struct pthread_cond_monotonic *monotonic_conds = NULL;
|
||||
|
||||
int pthread_cond_init_232(pthread_cond_t *restrict cond, const pthread_condattr_t *restrict attr)
|
||||
{
|
||||
clockid_t clock_id;
|
||||
int result;
|
||||
|
||||
result = real_pthread_cond_init_232(cond, attr);
|
||||
|
||||
if (result != 0 || attr == NULL)
|
||||
return result;
|
||||
|
||||
pthread_condattr_getclock(attr, &clock_id);
|
||||
|
||||
if (clock_id == CLOCK_MONOTONIC) {
|
||||
struct pthread_cond_monotonic *e = (struct pthread_cond_monotonic*)malloc(sizeof(struct pthread_cond_monotonic));
|
||||
e->ptr = cond;
|
||||
HASH_ADD_PTR(monotonic_conds, ptr, e);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int pthread_cond_destroy_232(pthread_cond_t *cond)
|
||||
{
|
||||
struct pthread_cond_monotonic* e;
|
||||
HASH_FIND_PTR(monotonic_conds, &cond, e);
|
||||
if (e) {
|
||||
HASH_DEL(monotonic_conds, e);
|
||||
free(e);
|
||||
}
|
||||
|
||||
return real_pthread_cond_destroy_232(cond);
|
||||
}
|
||||
|
||||
int pthread_cond_timedwait_common(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime, ft_lib_compat_pthread compat)
|
||||
{
|
||||
struct timespec tp, tdiff_actual, realtime, faketime;
|
||||
struct timespec *tf = NULL;
|
||||
struct pthread_cond_monotonic* e;
|
||||
clockid_t clk_id;
|
||||
int result;
|
||||
|
||||
if (abstime != NULL)
|
||||
{
|
||||
HASH_FIND_PTR(monotonic_conds, &cond, e);
|
||||
if (e != NULL)
|
||||
clk_id = CLOCK_MONOTONIC;
|
||||
else
|
||||
clk_id = CLOCK_REALTIME;
|
||||
|
||||
DONT_FAKE_TIME(result = (*real_clock_gettime)(clk_id, &realtime));
|
||||
if (result == -1)
|
||||
{
|
||||
return EINVAL;
|
||||
}
|
||||
faketime = realtime;
|
||||
(void)fake_clock_gettime(clk_id, &faketime);
|
||||
|
||||
timespecsub(abstime, &faketime, &tp);
|
||||
if (user_rate_set)
|
||||
{
|
||||
timespecmul(&tp, 1.0 / user_rate, &tdiff_actual);
|
||||
}
|
||||
else
|
||||
{
|
||||
tdiff_actual = tp;
|
||||
}
|
||||
|
||||
/* For CLOCK_MONOTONIC, pthread_cond_timedwait uses clock_gettime
|
||||
internally to calculate the appropriate duration for the
|
||||
waiting time. This already uses the faked functions, hence, the
|
||||
fake time needs to be passed to pthread_cond_timedwait for
|
||||
CLOCK_MONOTONIC. */
|
||||
if(clk_id == CLOCK_MONOTONIC)
|
||||
timespecadd(&faketime, &tdiff_actual, &tp);
|
||||
else
|
||||
timespecadd(&realtime, &tdiff_actual, &tp);
|
||||
|
||||
tf = &tp;
|
||||
}
|
||||
|
||||
switch (compat) {
|
||||
case FT_COMPAT_GLIBC_2_3_2:
|
||||
result = real_pthread_cond_timedwait_232(cond, mutex, tf);
|
||||
break;
|
||||
case FT_COMPAT_GLIBC_2_2_5:
|
||||
result = real_pthread_cond_timedwait_225(cond, mutex, tf);
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int pthread_cond_timedwait_225(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
|
||||
{
|
||||
return pthread_cond_timedwait_common(cond, mutex, abstime, FT_COMPAT_GLIBC_2_2_5);
|
||||
}
|
||||
|
||||
int pthread_cond_timedwait_232(pthread_cond_t *cond, pthread_mutex_t *mutex, const struct timespec *abstime)
|
||||
{
|
||||
return pthread_cond_timedwait_common(cond, mutex, abstime, FT_COMPAT_GLIBC_2_3_2);
|
||||
}
|
||||
|
||||
__asm__(".symver pthread_cond_timedwait_225, pthread_cond_timedwait@GLIBC_2.2.5");
|
||||
__asm__(".symver pthread_cond_timedwait_232, pthread_cond_timedwait@@GLIBC_2.3.2");
|
||||
__asm__(".symver pthread_cond_init_232, pthread_cond_init@@GLIBC_2.3.2");
|
||||
__asm__(".symver pthread_cond_destroy_232, pthread_cond_destroy@@GLIBC_2.3.2");
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Editor modelines
|
||||
*
|
||||
|
||||
@@ -4,7 +4,18 @@ GLIBC_2.2 {
|
||||
timer_gettime; timer_settime;
|
||||
local: timer_settime_*; timer_gettime_*;
|
||||
};
|
||||
|
||||
GLIBC_2.3.3 {
|
||||
# Changed timer_t.
|
||||
timer_gettime; timer_settime;
|
||||
} GLIBC_2.2;
|
||||
|
||||
GLIBC_2.2.5 {
|
||||
global: pthread_cond_timedwait;
|
||||
local: pthread_cond_timedwait_*; pthread_cond_init_*; pthread_cond_destroy*;
|
||||
};
|
||||
|
||||
GLIBC_2.3.2 {
|
||||
pthread_cond_timedwait; pthread_cond_init; pthread_cond_destroy;
|
||||
} GLIBC_2.2.5;
|
||||
|
||||
|
||||
1208
src/uthash.h
Normal file
1208
src/uthash.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -1,7 +1,7 @@
|
||||
CC = gcc
|
||||
|
||||
CFLAGS = -std=gnu99 -Wall -DFAKE_STAT -Werror -Wextra
|
||||
LDFLAGS = -lrt
|
||||
LDFLAGS = -lrt -lpthread
|
||||
|
||||
SRC = timetest.c
|
||||
OBJ = ${SRC:.c=.o}
|
||||
|
||||
@@ -47,7 +47,7 @@ echo
|
||||
echo "============================================================================="
|
||||
echo
|
||||
|
||||
echo "Running the test program with 10 days postive offset specified, and sped up 2 times"
|
||||
echo "Running the test program with 10 days positive offset specified, and sped up 2 times"
|
||||
echo "\$ LD_PRELOAD=../src/libfaketime.so.1 FAKETIME=\"+10d x2\" ./timetest"
|
||||
LD_PRELOAD=../src/libfaketime.so.1 FAKETIME="+10d x2" NO_FAKE_STAT=1 ./timetest
|
||||
echo
|
||||
|
||||
@@ -33,7 +33,7 @@ echo "FAKETIME=\"-10d\" NO_FAKE_STAT=1 ./timetest"
|
||||
FAKETIME="-10d" NO_FAKE_STAT=1 ./timetest
|
||||
echo
|
||||
|
||||
echo "Running the test program with 10 days postive offset specified, and sped up 2 times"
|
||||
echo "Running the test program with 10 days positive offset specified, and sped up 2 times"
|
||||
echo "FAKETIME=\"+10d x2\" ./timetest"
|
||||
FAKETIME="+10d x2" NO_FAKE_STAT=1 ./timetest
|
||||
echo
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#define _GNU_SOURCE
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <time.h>
|
||||
@@ -31,6 +32,8 @@
|
||||
#endif
|
||||
|
||||
#ifndef __APPLE__
|
||||
#include <pthread.h>
|
||||
#include <errno.h>
|
||||
#include <signal.h>
|
||||
|
||||
#define VERBOSE 0
|
||||
@@ -49,6 +52,64 @@ handler(int sig, siginfo_t *si, void *uc)
|
||||
printf("Caught signal %d\n", sig);
|
||||
}
|
||||
}
|
||||
|
||||
void* pthread_test(void* args)
|
||||
{
|
||||
pthread_mutex_t fakeMutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
pthread_cond_t fakeCond = PTHREAD_COND_INITIALIZER;
|
||||
|
||||
pthread_cond_t monotonic_cond;
|
||||
pthread_condattr_t attr;
|
||||
|
||||
struct timespec timeToWait, now;
|
||||
int rt;
|
||||
|
||||
args = args; // silence compiler warning about unused argument
|
||||
|
||||
clock_gettime(CLOCK_REALTIME, &now);
|
||||
timeToWait.tv_sec = now.tv_sec+1;
|
||||
timeToWait.tv_nsec = now.tv_nsec;
|
||||
|
||||
printf("pthread_cond_timedwait: CLOCK_REALTIME test\n");
|
||||
printf("(Intentionally sleeping 1 second...)\n");
|
||||
fflush(stdout);
|
||||
|
||||
pthread_mutex_lock(&fakeMutex);
|
||||
rt = pthread_cond_timedwait(&fakeCond, &fakeMutex, &timeToWait);
|
||||
if (rt != ETIMEDOUT)
|
||||
{
|
||||
printf("pthread_cond_timedwait failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
pthread_mutex_unlock(&fakeMutex);
|
||||
|
||||
|
||||
pthread_condattr_init(&attr);
|
||||
pthread_condattr_setclock(&attr, CLOCK_MONOTONIC);
|
||||
pthread_cond_init(&monotonic_cond, &attr);
|
||||
|
||||
clock_gettime(CLOCK_MONOTONIC, &now);
|
||||
timeToWait.tv_sec = now.tv_sec+1;
|
||||
timeToWait.tv_nsec = now.tv_nsec;
|
||||
|
||||
printf("pthread_cond_timedwait: CLOCK_MONOTONIC test\n");
|
||||
printf("(Intentionally sleeping 1 second...)\n");
|
||||
fflush(stdout);
|
||||
|
||||
pthread_mutex_lock(&fakeMutex);
|
||||
rt = pthread_cond_timedwait(&monotonic_cond, &fakeMutex, &timeToWait);
|
||||
if (rt != ETIMEDOUT)
|
||||
{
|
||||
printf("pthread_cond_timedwait failed\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
pthread_mutex_unlock(&fakeMutex);
|
||||
|
||||
pthread_cond_destroy(&monotonic_cond);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int main (int argc, char **argv)
|
||||
@@ -69,6 +130,12 @@ int main (int argc, char **argv)
|
||||
#endif
|
||||
|
||||
#ifndef __APPLE__
|
||||
pthread_t thread;
|
||||
void *ret;
|
||||
|
||||
pthread_create(&thread, NULL, pthread_test, NULL);
|
||||
pthread_join(thread, &ret);
|
||||
|
||||
sa.sa_flags = SA_SIGINFO;
|
||||
sa.sa_sigaction = handler;
|
||||
sigemptyset(&sa.sa_mask);
|
||||
|
||||
Reference in New Issue
Block a user