New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix runtime problems on MacOS using M1 chips #2579
Changes from all commits
fc56c2e
18fd7ec
261e537
359f778
f3378f7
3a2c29d
fddbb64
b65b069
7bd1ab5
e48cff5
c6eac08
8815660
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -7,13 +7,21 @@ | |
#include <sys/wait.h> | ||
#include <sys/time.h> | ||
#include <unordered_map> | ||
#ifdef __APPLE__ | ||
// Semaphores on OSX are deprectated | ||
#include <dispatch/dispatch.h> | ||
#else | ||
#include <semaphore.h> | ||
#include <errno.h> | ||
#include <sys/mman.h> | ||
#include <unistd.h> | ||
#include <stdio.h> | ||
#include <stdlib.h> | ||
#include <fcntl.h> | ||
|
||
// The +1 accounts for the null char at the end of the name | ||
#ifdef __APPLE__ | ||
#include <sys/posix_sem.h> | ||
#define SEM_MAX_LENGTH PSEMNAMLEN + 1 | ||
#else | ||
#include <limits.h> | ||
#define SEM_MAX_LENGTH _POSIX_PATH_MAX + 1 | ||
Comment on lines
+18
to
+24
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is and creation of semaphore is copy-pasted from Phase.c in Commix impl. In both cases this is needed due to problems on MacOs - usage of sem_create would return -1 and errno would mention not implemented error. |
||
#endif | ||
|
||
struct Monitor { | ||
|
@@ -33,24 +41,16 @@ struct Monitor { | |
static pthread_mutex_t shared_mutex; | ||
static std::unordered_map<int, std::shared_ptr<Monitor>> waiting_procs; | ||
static std::unordered_map<int, int> finished_procs; | ||
#ifdef __APPLE__ | ||
static dispatch_semaphore_t active_procs; | ||
#else | ||
static sem_t *active_procs; | ||
#endif | ||
|
||
static void *wait_loop(void *arg) { | ||
while (1) { | ||
|
||
// Wait until there is at least 1 active process | ||
#ifdef __APPLE__ | ||
dispatch_semaphore_wait(active_procs, DISPATCH_TIME_FOREVER); | ||
#else | ||
// Wait until there is at least 1 active process | ||
int wait_result; | ||
do { | ||
wait_result = sem_wait(active_procs); | ||
} while (wait_result == -1 && errno == EINTR); | ||
#endif | ||
|
||
int status; | ||
const int pid = waitpid(-1, &status, 0); | ||
|
@@ -87,13 +87,7 @@ static int check_result(const int pid, pthread_mutex_t *lock) { | |
|
||
extern "C" { | ||
/* Notify process monitor about spawning new process */ | ||
void scalanative_process_monitor_notify() { | ||
#ifdef __APPLE__ | ||
dispatch_semaphore_signal(active_procs); | ||
#else | ||
sem_post(active_procs); | ||
#endif | ||
} | ||
void scalanative_process_monitor_notify() { sem_post(active_procs); } | ||
|
||
int scalanative_process_monitor_check_result(const int pid) { | ||
pthread_mutex_lock(&shared_mutex); | ||
|
@@ -128,14 +122,22 @@ int scalanative_process_monitor_wait_for_pid(const int pid, timespec *ts, | |
void scalanative_process_monitor_init() { | ||
pthread_t thread; | ||
pthread_mutex_init(&shared_mutex, NULL); | ||
#ifdef __APPLE__ | ||
active_procs = dispatch_semaphore_create(0); | ||
#else | ||
// place semaphore in shared memory (needed for arm64) | ||
active_procs = (sem_t *)mmap(NULL, sizeof(sem_t *), PROT_READ | PROT_WRITE, | ||
MAP_SHARED | MAP_ANONYMOUS, -1, 0); | ||
sem_init(active_procs, 1, 0); | ||
#endif | ||
|
||
// MacOs might not allow for usage of anonymous semaphores (not implemented | ||
// on M1 chips) leading to deadlocks | ||
char semaphoreName[SEM_MAX_LENGTH]; | ||
snprintf(semaphoreName, SEM_MAX_LENGTH, "__sn_%d-process-monitor", | ||
getpid()); | ||
active_procs = sem_open(semaphoreName, O_CREAT | O_EXCL, 0644, 0); | ||
if (active_procs == SEM_FAILED) { | ||
perror("Failed to create or open process monitor semaphore"); | ||
} | ||
// Delete semaphore on exit | ||
if (sem_unlink(semaphoreName) != 0) { | ||
fprintf(stderr, "Unlinking process monitor semaphore failed\n"); | ||
exit(errno); | ||
} | ||
|
||
pthread_create(&thread, NULL, wait_loop, NULL); | ||
pthread_detach(thread); | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -71,6 +71,8 @@ object CVarArgList { | |
)(implicit z: Zone): CVarArgList = { | ||
if (isWindows) | ||
toCVarArgList_X86_64_Windows(varargs) | ||
else if (PlatformExt.isArm64 && Platform.isMac()) | ||
toCVarArgList_Arm64_MacOS(varargs) | ||
else | ||
toCVarArgList_Unix(varargs) | ||
} | ||
|
@@ -216,4 +218,48 @@ object CVarArgList { | |
new CVarArgList(resultStorage) | ||
} | ||
|
||
private def toCVarArgList_Arm64_MacOS( | ||
varargs: Seq[CVarArg] | ||
)(implicit z: Zone) = { | ||
val alignedArgs = varargs.map { arg => | ||
arg.value match { | ||
case value: Byte => | ||
value.toLong: CVarArg | ||
case value: Short => | ||
value.toLong: CVarArg | ||
case value: Int => | ||
value.toLong: CVarArg | ||
case value: UByte => | ||
value.toULong: CVarArg | ||
case value: UShort => | ||
value.toULong: CVarArg | ||
case value: UInt => | ||
value.toULong: CVarArg | ||
case value: Float => | ||
value.toDouble: CVarArg | ||
case o => arg | ||
} | ||
} | ||
Comment on lines
+221
to
+242
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This implementation is exactly the same as for the x86 (in 32bit support branch), the only difference comes from mapping to Int64 instead of Int32 |
||
|
||
var totalSize = 0.toULong | ||
alignedArgs.foreach { vararg => | ||
val tag = vararg.tag | ||
totalSize = Tag.align(totalSize, tag.alignment) + tag.size | ||
} | ||
|
||
val argListStorage = z.alloc(totalSize).asInstanceOf[Ptr[Byte]] | ||
var currentIndex = 0.toULong | ||
alignedArgs.foreach { vararg => | ||
val tag = vararg.tag | ||
currentIndex = Tag.align(currentIndex, tag.alignment) | ||
tag.store( | ||
(argListStorage + currentIndex).asInstanceOf[Ptr[Any]], | ||
vararg.value | ||
) | ||
currentIndex += tag.size | ||
} | ||
|
||
new CVarArgList(toRawPtr(argListStorage)) | ||
} | ||
|
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On MacOS M1 the files created by copying were given empty permissions, this should match the permission of files created by the JVM