Skip to content

Commit

Permalink
Add SystemNative_LowLevelMonitor_TimedWait to System.Native (dotnet#4…
Browse files Browse the repository at this point in the history
…7325)

* Add SystemNative_LowLevelMonitor_TimedWait to System.Native

* Undefine _XOPEN_SOURCE before pthread.h to fix CoreCLR MacOS build

* Rework pthread_condattr_setclock/CLOCK_MONOTONIC logic to support iOS

* Try redefining _XOPEN_SOURCE

* Fix header for pthread_condattr_setclock check

* Copy check from CoreCLR GC
  • Loading branch information
CoffeeFlux authored Feb 8, 2021
1 parent 8dd3543 commit d5be845
Show file tree
Hide file tree
Showing 6 changed files with 80 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ internal static partial class Sys
[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_LowLevelMonitor_Wait")]
internal static extern void LowLevelMonitor_Wait(IntPtr monitor);

[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_LowLevelMonitor_TimedWait")]
internal static extern bool LowLevelMonitor_TimedWait(IntPtr monitor, int timeoutMilliseconds);

[DllImport(Libraries.SystemNative, EntryPoint = "SystemNative_LowLevelMonitor_Signal_Release")]
internal static extern void LowLevelMonitor_Signal_Release(IntPtr monitor);
}
Expand Down
1 change: 1 addition & 0 deletions src/libraries/Native/Unix/Common/pal_config.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@
#cmakedefine01 HAVE_CLOCK_MONOTONIC
#cmakedefine01 HAVE_CLOCK_REALTIME
#cmakedefine01 HAVE_CLOCK_GETTIME_NSEC_NP
#cmakedefine01 HAVE_PTHREAD_CONDATTR_SETCLOCK
#cmakedefine01 HAVE_TCP_H_TCPSTATE_ENUM
#cmakedefine01 HAVE_TCP_FSM_H
#cmakedefine01 HAVE_GSSFW_HEADERS
Expand Down
1 change: 1 addition & 0 deletions src/libraries/Native/Unix/System.Native/entrypoints.c
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ static const Entry s_sysNative[] =
DllImportEntry(SystemNative_LowLevelMonitor_Acquire)
DllImportEntry(SystemNative_LowLevelMonitor_Release)
DllImportEntry(SystemNative_LowLevelMonitor_Wait)
DllImportEntry(SystemNative_LowLevelMonitor_TimedWait)
DllImportEntry(SystemNative_LowLevelMonitor_Signal_Release)
DllImportEntry(SystemNative_UTimensat)
DllImportEntry(SystemNative_GetTimestamp)
Expand Down
74 changes: 70 additions & 4 deletions src/libraries/Native/Unix/System.Native/pal_threading.c
Original file line number Diff line number Diff line change
@@ -1,15 +1,25 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

#include "pal_config.h"
#include "pal_threading.h"

#include <limits.h>
#include <sched.h>
#include <assert.h>
#include <stdbool.h>
#include <stdlib.h>
#include <errno.h>
#include <time.h>

#if defined(TARGET_OSX)
// So we can use the declaration of pthread_cond_timedwait_relative_np
#undef _XOPEN_SOURCE
#endif
#include <pthread.h>
#if defined(TARGET_OSX)
#define _XOPEN_SOURCE
#endif

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// LowLevelMonitor - Represents a non-recursive mutex and condition
Expand Down Expand Up @@ -51,20 +61,46 @@ LowLevelMonitor* SystemNative_LowLevelMonitor_Create()
return NULL;
}

error = pthread_cond_init(&monitor->Condition, NULL);
#if HAVE_PTHREAD_CONDATTR_SETCLOCK && HAVE_CLOCK_MONOTONIC
pthread_condattr_t conditionAttributes;
error = pthread_condattr_init(&conditionAttributes);
if (error != 0)
{
error = pthread_mutex_destroy(&monitor->Mutex);
goto mutex_destroy;
}

error = pthread_condattr_setclock(&conditionAttributes, CLOCK_MONOTONIC);
if (error != 0)
{
error = pthread_condattr_destroy(&conditionAttributes);
assert(error == 0);
free(monitor);
return NULL;
goto mutex_destroy;
}

error = pthread_cond_init(&monitor->Condition, &conditionAttributes);

int condAttrDestroyError = pthread_condattr_destroy(&conditionAttributes);
assert(condAttrDestroyError == 0);
(void)condAttrDestroyError; // unused in release build
#else
error = pthread_cond_init(&monitor->Condition, NULL);
#endif
if (error != 0)
{
goto mutex_destroy;
}

#ifdef DEBUG
monitor->IsLocked = false;
#endif

return monitor;

mutex_destroy:
error = pthread_mutex_destroy(&monitor->Mutex);
assert(error == 0);
free(monitor);
return NULL;
}

void SystemNative_LowLevelMonitor_Destroy(LowLevelMonitor* monitor)
Expand Down Expand Up @@ -119,6 +155,36 @@ void SystemNative_LowLevelMonitor_Wait(LowLevelMonitor* monitor)
SetIsLocked(monitor, true);
}

int32_t SystemNative_LowLevelMonitor_TimedWait(LowLevelMonitor *monitor, int32_t timeoutMilliseconds)
{
assert(timeoutMilliseconds >= 0);

SetIsLocked(monitor, false);

int error;

// Calculate the time at which a timeout should occur, and wait. Older versions of OSX don't support clock_gettime with
// CLOCK_MONOTONIC, so we instead compute the relative timeout duration, and use a relative variant of the timed wait.
struct timespec timeoutTimeSpec;
#if HAVE_CLOCK_GETTIME_NSEC_NP
timeoutTimeSpec.tv_sec = timeoutMilliseconds / 1000;
timeoutTimeSpec.tv_nsec = (timeoutMilliseconds % 1000) * 1000 * 1000;
error = pthread_cond_timedwait_relative_np(&monitor->Condition, &monitor->Mutex, &timeoutTimeSpec);
#else
error = clock_gettime(CLOCK_MONOTONIC, &timeoutTimeSpec);
assert(error == 0);
uint64_t nanoseconds = (uint64_t)timeoutMilliseconds * 1000 * 1000 + (uint64_t)timeoutTimeSpec.tv_nsec;
timeoutTimeSpec.tv_sec += nanoseconds / (1000 * 1000 * 1000);
timeoutTimeSpec.tv_nsec = nanoseconds % (1000 * 1000 * 1000);
error = pthread_cond_timedwait(&monitor->Condition, &monitor->Mutex, &timeoutTimeSpec);
#endif
assert(error == 0 || error == ETIMEDOUT);

SetIsLocked(monitor, true);

return error == 0;
}

void SystemNative_LowLevelMonitor_Signal_Release(LowLevelMonitor* monitor)
{
assert(monitor != NULL);
Expand Down
2 changes: 2 additions & 0 deletions src/libraries/Native/Unix/System.Native/pal_threading.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,4 +18,6 @@ PALEXPORT void SystemNative_LowLevelMonitor_Release(LowLevelMonitor* monitor);

PALEXPORT void SystemNative_LowLevelMonitor_Wait(LowLevelMonitor* monitor);

PALEXPORT int32_t SystemNative_LowLevelMonitor_TimedWait(LowLevelMonitor *monitor, int32_t timeoutMilliseconds);

PALEXPORT void SystemNative_LowLevelMonitor_Signal_Release(LowLevelMonitor* monitor);
3 changes: 3 additions & 0 deletions src/libraries/Native/Unix/configure.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ include(CheckStructHasMember)
include(CheckSymbolExists)
include(CheckTypeSize)
include(CMakePushCheckState)
include(CheckLibraryExists)

# CMP0075 Include file check macros honor CMAKE_REQUIRED_LIBRARIES.
if(POLICY CMP0075)
Expand Down Expand Up @@ -587,6 +588,8 @@ check_symbol_exists(
time.h
HAVE_CLOCK_GETTIME_NSEC_NP)

check_library_exists(pthread pthread_condattr_setclock "" HAVE_PTHREAD_CONDATTR_SETCLOCK)

check_symbol_exists(
futimes
sys/time.h
Expand Down

0 comments on commit d5be845

Please sign in to comment.