Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 39 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ add_executable(datum_gateway
src/datum_jsonrpc.c
src/datum_logger.c
src/datum_protocol.c
src/portable_mutex.c
src/datum_queue.c
src/datum_sockets.c
src/datum_stratum.c
Expand Down Expand Up @@ -79,6 +80,16 @@ endif()

set(ARGP_LIBS "")
check_function_exists(argp_parse HAVE_ARGP_PARSE)
if(APPLE AND NOT HAVE_ARGP_PARSE)
find_library(ARGP_LIBRARY NAMES argp libargp HINTS /opt/homebrew/lib)
if(ARGP_LIBRARY)
list(APPEND ARGP_LIBS ${ARGP_LIBRARY})
include_directories(SYSTEM /opt/homebrew/include)
else()
message(FATAL_ERROR "libargp not found. Please install it with `brew install argp-standalone`.")
endif()
endif()

if(NOT HAVE_ARGP_PARSE)
check_library_exists(argp argp_parse "" ARGP)
if(NOT ARGP AND CMAKE_SYSTEM_NAME STREQUAL "FreeBSD")
Expand All @@ -91,12 +102,39 @@ if(NOT HAVE_ARGP_PARSE)
endif()
endif()

# Ensure pkg-config can find Homebrew-installed packages on macOS
if(APPLE)
set(ENV{PKG_CONFIG_PATH} "/opt/homebrew/lib/pkgconfig:$ENV{PKG_CONFIG_PATH}")
endif()

check_function_exists(epoll_wait HAVE_EPOLL_WAIT)
if(HAVE_EPOLL_WAIT)
set(EPOLL_SHIM_INCLUDE_DIRS "")
set(EPOLL_SHIM_LIBRARIES "")
else()
pkg_check_modules(EPOLL_SHIM REQUIRED epoll-shim)
pkg_check_modules(EPOLL_SHIM REQUIRED epoll-shim)
if(APPLE)
if(NOT EPOLL_SHIM_FOUND)
message(FATAL_ERROR "epoll-shim not found. Install it with `brew install epoll-shim`.")
endif()
# Add include directories
target_include_directories(datum_gateway
PUBLIC
${EPOLL_SHIM_INCLUDE_DIRS}
)

# Add link directories
target_link_directories(datum_gateway
PUBLIC
${EPOLL_SHIM_LIBRARY_DIRS}
)

# Add linker flags (e.g. -L... -lepoll-shim)
target_link_libraries(datum_gateway
PUBLIC
${EPOLL_SHIM_LDFLAGS}
)
endif()
endif()

cmake_pop_check_state()
Expand Down
55 changes: 43 additions & 12 deletions src/datum_protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@
#include "datum_queue.h"
#include "git_version.h"


#ifdef __APPLE__
#include "portable_mutex.h"
#endif
atomic_int datum_protocol_client_active = 0;

DATUM_ENC_KEYS local_datum_keys;
Expand Down Expand Up @@ -265,6 +269,11 @@ int datum_protocol_mining_cmd(void *data, int len) {
}

pthread_mutex_t datum_protocol_coinbaser_fetch_mutex = PTHREAD_MUTEX_INITIALIZER;
#ifdef __APPLE__
// Declare the state for the timed mutex only for Apple
static timed_mutex_state_t datum_protocol_coinbaser_fetch_state;
#endif

pthread_cond_t datum_protocol_coinbaser_fetch_cond = PTHREAD_COND_INITIALIZER;
unsigned char datum_coinbaser_v2_response_buf[2][32768] = { 0 };
unsigned char *datum_coinbaser_v2_response = NULL;
Expand Down Expand Up @@ -293,8 +302,11 @@ int datum_protocol_coinbaser_fetch_response(int len, unsigned char *data) {
DLOG_DEBUG("Invalid coinbaser received! %lu %lu", (unsigned long)x, (unsigned long)(len-12));
return 0;
}

rc = pthread_mutex_timedlock(&datum_protocol_coinbaser_fetch_mutex, &ts);
#ifdef __APPLE__
rc = apple_mutex_timedlock(&datum_protocol_coinbaser_fetch_mutex, &datum_protocol_coinbaser_fetch_state, &ts);
#else
rc = pthread_mutex_timedlock(&datum_protocol_coinbaser_fetch_mutex, &ts);
#endif
if (rc != 0) {
DLOG_DEBUG("Could not get a lock on the coinbaser reception mutex after 5 seconds... bug?");
return 0;
Expand All @@ -312,8 +324,12 @@ int datum_protocol_coinbaser_fetch_response(int len, unsigned char *data) {
datum_coinbaser_v2_response_len[datum_coinbaser_v2_response_buf_idx] = x;

pthread_cond_signal(&datum_protocol_coinbaser_fetch_cond); // Signal the condition variable
pthread_mutex_unlock(&datum_protocol_coinbaser_fetch_mutex);


#ifdef __APPLE__
apple_mutex_unlock(&datum_protocol_coinbaser_fetch_mutex, &datum_protocol_coinbaser_fetch_state);
#else
pthread_mutex_unlock(&datum_protocol_coinbaser_fetch_mutex);
#endif
return 1;
}

Expand Down Expand Up @@ -356,19 +372,29 @@ int datum_protocol_coinbaser_fetch(void *sptr) {
// spin here for up to 5 seconds while awaiting a coinbaser response from DATUM Prime
clock_gettime(CLOCK_REALTIME, &ts);
ts.tv_sec += 5; // Set timeout to 5 seconds

pthread_mutex_lock(&datum_protocol_coinbaser_fetch_mutex);

#ifdef __APPLE__
apple_mutex_lock(&datum_protocol_coinbaser_fetch_mutex, &datum_protocol_coinbaser_fetch_state);
#else
pthread_mutex_lock(&datum_protocol_coinbaser_fetch_mutex);
#endif
rc = pthread_cond_timedwait(&datum_protocol_coinbaser_fetch_cond, &datum_protocol_coinbaser_fetch_mutex, &ts);
if (rc == ETIMEDOUT) {
pthread_mutex_unlock(&datum_protocol_coinbaser_fetch_mutex);
#ifdef __APPLE__
apple_mutex_unlock(&datum_protocol_coinbaser_fetch_mutex, &datum_protocol_coinbaser_fetch_state);
#else
pthread_mutex_unlock(&datum_protocol_coinbaser_fetch_mutex);
#endif
DLOG_DEBUG("Timeout waiting for coinbaser response from DATUM Prime");
return 0;
}

if (rc != 0) {
DLOG_DEBUG("Error waiting for coinbaser response from DATUM Prime");
pthread_mutex_unlock(&datum_protocol_coinbaser_fetch_mutex);
#ifdef __APPLE__
apple_mutex_unlock(&datum_protocol_coinbaser_fetch_mutex, &datum_protocol_coinbaser_fetch_state);
#else
pthread_mutex_unlock(&datum_protocol_coinbaser_fetch_mutex);
#endif
return 0;
}
i = 0;
Expand All @@ -377,8 +403,11 @@ int datum_protocol_coinbaser_fetch(void *sptr) {
if ((datum_coinbaser_v2_response) && (datum_coinbaser_v2_response_value[datum_coinbaser_v2_response_buf_idx] == value)) {
i = datum_coinbaser_v2_parse(s, datum_coinbaser_v2_response, datum_coinbaser_v2_response_len[datum_coinbaser_v2_response_buf_idx], false);
}

pthread_mutex_unlock(&datum_protocol_coinbaser_fetch_mutex);
#ifdef __APPLE__
apple_mutex_unlock(&datum_protocol_coinbaser_fetch_mutex, &datum_protocol_coinbaser_fetch_state);
#else
pthread_mutex_unlock(&datum_protocol_coinbaser_fetch_mutex);
#endif
return i;
}

Expand Down Expand Up @@ -1913,7 +1942,9 @@ int datum_protocol_init(void) {
DLOG_WARN("****************************************************");
return 0;
}

#ifdef __APPLE__
apple_timed_mutex_init(&datum_protocol_coinbaser_fetch_state);
#endif
if (sodium_init() < 0) {
DLOG_FATAL("libsodium initialization failed");
return -1;
Expand Down
48 changes: 48 additions & 0 deletions src/portable_mutex.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#include "portable_mutex.h"

#ifdef __APPLE__
void apple_timed_mutex_init(timed_mutex_state_t *state) {
pthread_cond_init(&state->cond, NULL);
state->locked = 0;
}

int apple_mutex_timedlock(pthread_mutex_t *mutex, timed_mutex_state_t *state, const struct timespec *abstime) {
int rc;
pthread_mutex_lock(mutex);
while (state->locked) {
rc = pthread_cond_timedwait(&state->cond, mutex, abstime);
if (rc == ETIMEDOUT) {
pthread_mutex_unlock(mutex);
return ETIMEDOUT;
}
if (rc != 0) {
pthread_mutex_unlock(mutex);
return rc;
}
}
state->locked = 1;
pthread_mutex_unlock(mutex);
return 0;
}

void apple_mutex_lock(pthread_mutex_t *mutex, timed_mutex_state_t *state) {
pthread_mutex_lock(mutex);
while (state->locked) {
pthread_cond_wait(&state->cond, mutex);
}
state->locked = 1;
pthread_mutex_unlock(mutex);
}

void apple_mutex_unlock(pthread_mutex_t *mutex, timed_mutex_state_t *state) {
pthread_mutex_lock(mutex);
state->locked = 0;
pthread_cond_signal(&state->cond);
pthread_mutex_unlock(mutex);
}

void apple_timed_mutex_destroy(timed_mutex_state_t *state) {
pthread_cond_destroy(&state->cond);
}
#endif // __APPLE__

24 changes: 24 additions & 0 deletions src/portable_mutex.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
#ifndef PORTABLE_MUTEX_H
#define PORTABLE_MUTEX_H

#ifdef __APPLE__
#include <pthread.h>
#include <time.h>
#include <errno.h>

// A struct to manage the state for a timed mutex on Apple
typedef struct {
pthread_cond_t cond;
int locked;
} timed_mutex_state_t;

// State management functions for timed mutexes on Apple
void apple_timed_mutex_init(timed_mutex_state_t *state);
int apple_mutex_timedlock(pthread_mutex_t *mutex, timed_mutex_state_t *state, const struct timespec *abstime);
void apple_mutex_lock(pthread_mutex_t *mutex, timed_mutex_state_t *state);
void apple_mutex_unlock(pthread_mutex_t *mutex, timed_mutex_state_t *state);
void apple_timed_mutex_destroy(timed_mutex_state_t *state);
#endif // __APPLE__

#endif // PORTABLE_MUTEX_H