1 module mecca.platform.os.darwin; 2 3 version (Darwin): 4 package(mecca): 5 6 public import mecca.platform.os.darwin.ucontext; 7 public import mecca.platform.os.darwin.time; 8 9 import core.sys.posix.sys.types : pthread_t; 10 11 import mecca.platform.os : MmapArguments; 12 13 // These two do not exist on Darwin platforms. We'll just use a value that won't 14 // have any affect when used together with mmap and mremap. 15 enum MAP_POPULATE = 0; 16 enum MREMAP_MAYMOVE = 0; 17 18 /// 19 enum OSSignal 20 { 21 SIGNONE = 0, /// invalid 22 SIGHUP = 1, /// hangup 23 SIGINT = 2, /// interrupt 24 SIGQUIT = 3, /// quit 25 SIGILL = 4, /// illegal instruction (not reset when caught) 26 SIGTRAP = 5, /// trace trap (not reset when caught) 27 SIGABRT = 6, /// abort() 28 SIGIOT = SIGABRT, /// compatibility 29 SIGEMT = 7, /// EMT instruction 30 SIGFPE = 8, /// floating point exception 31 SIGKILL = 9, /// kill (cannot be caught or ignored) 32 SIGBUS = 10, /// bus error 33 SIGSEGV = 11, /// segmentation violation 34 SIGSYS = 12, /// bad argument to system call 35 SIGPIPE = 13, /// write on a pipe with no one to read it 36 SIGALRM = 14, /// alarm clock 37 SIGTERM = 15, /// software termination signal from kill 38 SIGURG = 16, /// urgent condition on IO channel 39 SIGSTOP = 17, /// sendable stop signal not from tty 40 SIGTSTP = 18, /// stop signal from tty 41 SIGCONT = 19, /// continue a stopped process 42 SIGCHLD = 20, /// to parent on child stop or exit 43 SIGTTIN = 21, /// to readers pgrp upon background tty read 44 SIGTTOU = 22, /// like TTIN for output if (tp->t_local<OSTOP) 45 SIGIO = 23, /// input/output possible signal 46 SIGXCPU = 24, /// exceeded CPU time limit 47 SIGXFSZ = 25, /// exceeded file size limit 48 SIGVTALRM = 26, /// virtual time alarm 49 SIGPROF = 27, /// profiling time alarm 50 SIGWINCH = 28, /// window size changes 51 SIGINFO = 29, /// information request 52 SIGUSR1 = 30, /// user defined signal 1 53 SIGUSR2 = 31 /// user defined signal 2 54 } 55 56 /** 57 * Represents the ID of a thread. 58 * 59 * This type is platform dependent. 60 */ 61 alias ThreadId = ulong; 62 63 __gshared static immutable BLOCKED_SIGNALS = [ 64 OSSignal.SIGHUP, OSSignal.SIGINT, OSSignal.SIGQUIT, 65 //OSSignal.SIGILL, OSSignal.SIGTRAP, OSSignal.SIGABRT, 66 //OSSignal.SIGBUS, OSSignal.SIGFPE, OSSignal.SIGKILL, 67 //OSSignal.SIGUSR1, OSSignal.SIGSEGV, OSSignal.SIGUSR2, 68 OSSignal.SIGPIPE, OSSignal.SIGALRM, OSSignal.SIGTERM, 69 //OSSignal.SIGSTKFLT, OSSignal.SIGCONT, OSSignal.SIGSTOP, 70 OSSignal.SIGCHLD, OSSignal.SIGTSTP, OSSignal.SIGTTIN, 71 OSSignal.SIGTTOU, OSSignal.SIGURG, OSSignal.SIGXCPU, 72 OSSignal.SIGXFSZ, OSSignal.SIGVTALRM, OSSignal.SIGPROF, 73 OSSignal.SIGWINCH, OSSignal.SIGIO, 74 //OSSignal.SIGSYS, 75 ]; 76 77 extern (C) private int pthread_threadid_np(pthread_t, ulong*) nothrow; 78 79 /// Returns: the current thread ID 80 ThreadId currentThreadId() @system nothrow 81 { 82 import mecca.lib.exception : ASSERT; 83 84 enum assertMessage = "pthread_threadid_np failed, should not happen"; 85 86 ulong threadId; 87 ASSERT!"assertMessage"(pthread_threadid_np(null, &threadId) == 0); 88 89 return threadId; 90 } 91 92 enum O_CLOEXEC = 0x1000000; 93 enum F_DUPFD_CLOEXEC = 67; 94 95 // this does not exist on Darwin 96 enum EREMOTEIO = -1; 97 98 // `pipe2` does not exist on Darwin so we're emulating it instead. This is 99 // emulated by first calling the regular `pipe` followed by `fcntl` on the two 100 // file descriptors. This is not thread safe. 101 extern(C) private int pipe2(ref int[2] pipefd, int flags) nothrow @trusted @nogc 102 { 103 import core.sys.posix.unistd : close, pipe; 104 105 static int setFlags(int fd, int flags) 106 { 107 import core.sys.posix.fcntl : fcntl, F_SETFD, F_GETFD; 108 109 const existingFlags = fcntl(fd, F_GETFD); 110 111 if (existingFlags == -1) 112 return existingFlags; 113 114 return fcntl(fd, F_SETFD, existingFlags | flags); 115 } 116 117 static void closePipe(ref int[2] pipe) 118 { 119 foreach (fd; pipe) 120 close(fd); 121 } 122 123 const pipeResult = pipe(pipefd); 124 125 if (pipeResult != 0) 126 return pipeResult; 127 128 foreach (fd; pipefd) 129 { 130 if (setFlags(fd, flags) == -1) 131 { 132 closePipe(pipefd); 133 return -1; 134 } 135 } 136 137 return 0; 138 } 139 140 enum ITIMER_REAL = 0; 141 142 void* mremap(MmapArguments mmapArguments, void* oldAddress, size_t oldSize, 143 size_t newSize, int flags, void* newAddress = null) 144 { 145 import core.stdc..string : memcpy; 146 import core.sys.posix.sys.mman : mmap, munmap, MAP_FAILED; 147 148 if (oldSize == newSize) 149 return oldAddress; 150 151 if (newSize < oldSize) 152 { 153 const sizeToUnmap = oldSize - newSize; 154 if (munmap(oldAddress + sizeToUnmap, sizeToUnmap) != 0) 155 return MAP_FAILED; 156 157 return oldAddress; 158 } 159 160 auto newMemory = mmap(newAddress, newSize, mmapArguments.tupleof); 161 162 if (newMemory == MAP_FAILED) 163 return MAP_FAILED; 164 165 memcpy(newMemory, oldAddress, oldSize); 166 167 if (munmap(oldAddress, oldSize) != 0) 168 { 169 if (munmap(newMemory, newSize) != 0) 170 assert(false); 171 172 return MAP_FAILED; 173 } 174 175 return newMemory; 176 }