summaryrefslogtreecommitdiffstats
path: root/contrib/restricted/wavm/Lib/Platform/POSIX/EventPOSIX.cpp
blob: 461f250243f84e3d7dab6dab1b2a636f87095ba1 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
#include <errno.h>
#include <pthread.h>
#include <sys/time.h>
#include "WAVM/Inline/Assert.h"
#include "WAVM/Inline/Errors.h"
#include "WAVM/Inline/I128.h"
#include "WAVM/Inline/Time.h"
#include "WAVM/Platform/Clock.h"
#include "WAVM/Platform/Defines.h"
#include "WAVM/Platform/Event.h"

using namespace WAVM;
using namespace WAVM::Platform;

Platform::Event::Event()
{
	static_assert(sizeof(pthreadMutex) == sizeof(pthread_mutex_t), "");
	static_assert(alignof(PthreadMutex) >= alignof(pthread_mutex_t), "");

	static_assert(sizeof(pthreadCond) == sizeof(pthread_cond_t), "");
	static_assert(alignof(PthreadCond) >= alignof(pthread_cond_t), "");

	pthread_condattr_t conditionVariableAttr;
	WAVM_ERROR_UNLESS(!pthread_condattr_init(&conditionVariableAttr));

// Set the condition variable to use the monotonic clock for wait timeouts.
#ifndef __APPLE__
	WAVM_ERROR_UNLESS(!pthread_condattr_setclock(&conditionVariableAttr, CLOCK_MONOTONIC));
#endif

	WAVM_ERROR_UNLESS(!pthread_cond_init((pthread_cond_t*)&pthreadCond, nullptr));
	WAVM_ERROR_UNLESS(!pthread_mutex_init((pthread_mutex_t*)&pthreadMutex, nullptr));

	WAVM_ERROR_UNLESS(!pthread_condattr_destroy(&conditionVariableAttr));
}

Platform::Event::~Event()
{
	pthread_cond_destroy((pthread_cond_t*)&pthreadCond);
	WAVM_ERROR_UNLESS(!pthread_mutex_destroy((pthread_mutex_t*)&pthreadMutex));
}

bool Platform::Event::wait(Time waitDuration)
{
	WAVM_ERROR_UNLESS(!pthread_mutex_lock((pthread_mutex_t*)&pthreadMutex));

	int result;
	if(isInfinity(waitDuration))
	{
		result = pthread_cond_wait((pthread_cond_t*)&pthreadCond, (pthread_mutex_t*)&pthreadMutex);
	}
	else
	{
		// Use the non-POSIX relative time wait on Mac, and an absolute monotonic clock timeout on
		// other POSIX systems.
#ifdef __APPLE__
		timespec waitTimeSpec;
		waitTimeSpec.tv_sec = U64(waitDuration.ns / 1000000000);
		waitTimeSpec.tv_nsec = U64(waitDuration.ns % 1000000000);

		result = pthread_cond_timedwait_relative_np(
			(pthread_cond_t*)&pthreadCond, (pthread_mutex_t*)&pthreadMutex, &waitTimeSpec);
#else
		const I128 untilTimeNS = getClockTime(Clock::monotonic).ns + waitDuration.ns;
		timespec untilTimeSpec;
		untilTimeSpec.tv_sec = U64(untilTimeNS / 1000000000);
		untilTimeSpec.tv_nsec = U64(untilTimeNS % 1000000000);

		result = pthread_cond_timedwait(
			(pthread_cond_t*)&pthreadCond, (pthread_mutex_t*)&pthreadMutex, &untilTimeSpec);
#endif
	}

	WAVM_ERROR_UNLESS(!pthread_mutex_unlock((pthread_mutex_t*)&pthreadMutex));

	if(result == ETIMEDOUT) { return false; }
	else
	{
		WAVM_ERROR_UNLESS(!result);
		return true;
	}
}

void Platform::Event::signal()
{
	WAVM_ERROR_UNLESS(!pthread_cond_signal((pthread_cond_t*)&pthreadCond));
}