Standard setup for writing C inspired by Casey Muratori, Ryan Fleury, Mr. 4th Programmer, and others in the handmade community.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.
 
 
 

378 lignes
12 KiB

  1. #ifndef OS_IMPL_LINUX_C
  2. #define OS_IMPL_LINUX_C
  3. #include "os.h"
  4. #include "sys/mman.h"
  5. #include "sys/stat.h"
  6. #include "string.h" // memcpy TODO(dledda): replace memcpy with custom impl?
  7. #include "unistd.h" // POSIX Standard, read, write, close, open, etc.
  8. #include "pthread.h"
  9. #include "fcntl.h"
  10. #include "sys/epoll.h"
  11. #include "sys/socket.h"
  12. #include "arpa/inet.h"
  13. void *os_alloc(uint64 capacity) {
  14. return mmap(0, capacity, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
  15. }
  16. void os_commit(void *ptr) {
  17. }
  18. void os_decommit(void *ptr) {
  19. }
  20. void os_free(void *ptr, uint64 size) {
  21. int err = munmap(ptr, size);
  22. Assert(err != -1);
  23. }
  24. string os_readEntireFile(Arena *arena, string filename) {
  25. Scratch temp = scratchStart(&arena, 1);
  26. int input = open(cstring(temp.arena, filename), O_RDONLY);
  27. string readBuffer;
  28. if (input) {
  29. struct stat st;
  30. stat((char *)filename.str, &st);
  31. uint64 fsize = st.st_size;
  32. readBuffer = PushString(arena, fsize);
  33. int64 bytesRead = read(input, readBuffer.str, readBuffer.length);
  34. close(input);
  35. if (bytesRead == -1) {
  36. arenaPopTo(arena, readBuffer.str);
  37. return s("");
  38. }
  39. } else {
  40. readBuffer = s("");
  41. }
  42. scratchEnd(temp);
  43. return readBuffer;
  44. }
  45. bool os_writeEntireFile(Arena *arena, string filename, const byte *contents, uint64 contentsLength) {
  46. Scratch temp = scratchStart(&arena, 1);
  47. bool result = false;
  48. int output = open(cstring(temp.arena, filename), O_WRONLY);
  49. if (output) {
  50. int64 bytesWritten = write(output, contents, contentsLength);
  51. if (bytesWritten != -1) {
  52. result = true;
  53. }
  54. close(output);
  55. }
  56. scratchEnd(temp);
  57. return result;
  58. }
  59. bool os_fileAppend(Arena *arena, string filename, const byte *contents, uint64 contentsLength) {
  60. Scratch temp = scratchStart(&arena, 1);
  61. bool result = false;
  62. int output = open(cstring(temp.arena, filename), O_APPEND);
  63. if (output) {
  64. int bytesWritten = write(output, contents, contentsLength);
  65. if (bytesWritten != -1) {
  66. result = true;
  67. }
  68. close(output);
  69. }
  70. scratchEnd(temp);
  71. return result;
  72. }
  73. void os_println(StdStream target, const char *fmt, va_list argList) {
  74. Scratch temp = scratchStart(0, 0);
  75. uint64 origLen = calcStringLen(fmt);
  76. string fmtLn = PushString(temp.arena, origLen + 2);
  77. memcpy(fmtLn.str, fmt, origLen);
  78. fmtLn.str[fmtLn.length - 2] = '\n';
  79. fmtLn.str[fmtLn.length - 1] = '\0';
  80. string result = strPrintfv(temp.arena, fmtLn.str, argList);
  81. // TODO(djledda): finish implementation without cstdlib
  82. switch (target) {
  83. case StdStream_stdin:
  84. write(0, (const void *)result.str, result.length);
  85. break;
  86. case StdStream_stderr:
  87. write(2, (const void *)result.str, result.length);
  88. break;
  89. case StdStream_stdout:
  90. default:
  91. write(1, (const void *)result.str, result.length);
  92. break;
  93. }
  94. scratchEnd(temp);
  95. }
  96. void os_print(StdStream target, const char *fmt, va_list argList) {
  97. Scratch temp = scratchStart(0, 0);
  98. string result = strPrintfv(temp.arena, fmt, argList);
  99. // TODO(djledda): finish implementation without cstdlib
  100. switch (target) {
  101. case StdStream_stdin:
  102. write(0, (const void *)result.str, result.length);
  103. break;
  104. case StdStream_stderr:
  105. write(2, (const void *)result.str, result.length);
  106. break;
  107. case StdStream_stdout:
  108. default:
  109. write(1, (const void *)result.str, result.length);
  110. break;
  111. }
  112. scratchEnd(temp);
  113. }
  114. OS_Thread os_createThread(void *(*entry)(void *), void *ctx) {
  115. pthread_t handle;
  116. pthread_attr_t attr;
  117. pthread_attr_init(&attr);
  118. pthread_create(&handle, &attr, entry, ctx);
  119. pthread_attr_destroy(&attr);
  120. return (OS_Thread){ .id=handle };
  121. }
  122. DefineList(ServerEvent, ServerEvent);
  123. typedef struct EPollServerEvents EPollServerEvents;
  124. struct EPollServerEvents {
  125. int epollFd;
  126. int32 maxEvents;
  127. int32 numEvents;
  128. struct epoll_event *events;
  129. bool err;
  130. ServerEventList userEvents;
  131. };
  132. Server serverInit(ServerInitInfo info) {
  133. Arena *arena = arenaAlloc(info.memory);
  134. EPollServerEvents *events = PushStructZero(arena, EPollServerEvents);
  135. events->epollFd = epoll_create1(0);
  136. events->events = PushArrayZero(arena, struct epoll_event, info.maxEvents);
  137. events->maxEvents = info.maxEvents;
  138. events->numEvents = 0;
  139. events->userEvents = PushListZero(arena, ServerEventList, info.maxEvents);
  140. struct sockaddr_in6 *serverAddr = PushStructZero(arena, struct sockaddr_in6);
  141. serverAddr->sin6_family = AF_INET6;
  142. serverAddr->sin6_port = htons(info.port);
  143. serverAddr->sin6_addr = in6addr_loopback;
  144. Server server = {
  145. .arena=arena,
  146. .address=(Address *)serverAddr,
  147. .clients=PushListZero(arena, SocketList, info.concurrentClients),
  148. .listening=false,
  149. .port=info.port,
  150. .handle=(SocketHandle *)(uint64)socket(AF_INET6, SOCK_STREAM, 0 /* IPPROTO_TCP */),
  151. .events=(ServerEvents *)events,
  152. };
  153. fcntl((uint64)server.handle, F_SETFL, fcntl((uint64)server.handle, F_GETFL, 0) | O_NONBLOCK);
  154. struct epoll_event event = {
  155. .data.fd=(uint64)server.handle,
  156. .events=EPOLLIN | EPOLLET,
  157. };
  158. epoll_ctl(events->epollFd, EPOLL_CTL_ADD, (int64)server.handle, &event);
  159. int bindErr = bind((uint64)server.handle, (struct sockaddr *)serverAddr, sizeof(*serverAddr));
  160. if (bindErr == -1) {
  161. // TODO(dledda): handle err
  162. }
  163. return server;
  164. }
  165. void serverListen(Server *s) {
  166. int listenErr = listen((uint64)s->handle, s->clients.capacity);
  167. if (listenErr == -1) {
  168. s->listening = false;
  169. } else {
  170. s->listening = true;
  171. }
  172. }
  173. Socket *serverAccept(Server *s) {
  174. struct sockaddr_in6 *clientAddr = PushStructZero(s->arena, struct sockaddr_in6);
  175. socklen_t clientAddrLen = sizeof(*clientAddr);
  176. uint64 clientSockHandle = accept((int)(uint64)s->handle, (struct sockaddr *)clientAddr, &clientAddrLen);
  177. if (clientSockHandle == -1) {
  178. clientSockHandle = (uint64)NULL;
  179. } else {
  180. fcntl((uint64)clientSockHandle, F_SETFL, fcntl((uint64)clientSockHandle, F_GETFL, 0) | O_NONBLOCK);
  181. }
  182. struct epoll_event event = {
  183. .data.fd=clientSockHandle,
  184. .events=EPOLLIN | EPOLLET,
  185. };
  186. epoll_ctl(((EPollServerEvents *)s->events)->epollFd, EPOLL_CTL_ADD, clientSockHandle, &event);
  187. if (s->clients.length < s->clients.capacity) {
  188. AppendList(&s->clients, ((Socket){
  189. .handle=(SocketHandle *)(uint64)clientSockHandle,
  190. .address=(Address *)clientAddr,
  191. }));
  192. return &s->clients.data[s->clients.length - 1];
  193. } else {
  194. return PushStructZero(s->arena, Socket);
  195. }
  196. }
  197. ServerEvent *serverGetNextEvent(Server *s) {
  198. EPollServerEvents *serverEvents = ((EPollServerEvents *)s->events);
  199. if (serverEvents->userEvents.length == 0) {
  200. serverEvents->numEvents = epoll_wait(serverEvents->epollFd, serverEvents->events, serverEvents->maxEvents, -1);
  201. if (serverEvents->numEvents == -1) {
  202. serverEvents->err = true;
  203. serverEvents->numEvents = 0;
  204. } else {
  205. serverEvents->userEvents.length = serverEvents->numEvents;
  206. for (int32 i = 0; i < serverEvents->numEvents; i++) {
  207. struct epoll_event *ev = &serverEvents->events[i];
  208. if ((ev->events & EPOLLIN) && ev->data.fd == (int)(int64)s->handle) {
  209. serverEvents->userEvents.data[i] = (ServerEvent){
  210. .type=ServerEventType_AcceptClient,
  211. .tAcceptClient={},
  212. };
  213. } else if (ev->events & EPOLLIN) {
  214. int64 fd = serverEvents->events[i].data.fd;
  215. Socket *client = NULL;
  216. ServerEvent serverEv = {
  217. .type=ServerEventType_ClientMessage,
  218. };
  219. for (EachIn(s->clients, j)) {
  220. if ((int64)s->clients.data[j].handle == fd) {
  221. client = &s->clients.data[j];
  222. serverEv.tClientMessage.client = client;
  223. serverEv.tClientMessage.clientId = j;
  224. }
  225. }
  226. if (client == NULL) {
  227. serverEv.type = ServerEventType_None;
  228. } else {
  229. serverEvents->userEvents.data[i] = serverEv;
  230. }
  231. }
  232. }
  233. }
  234. }
  235. if (serverEvents->userEvents.length == 0) {
  236. AppendList(&serverEvents->userEvents, (ServerEvent){ .type=ServerEventType_None });
  237. }
  238. // Pop next event
  239. serverEvents->userEvents.length--;
  240. return &serverEvents->userEvents.data[serverEvents->userEvents.length];
  241. }
  242. int64 socketRead(Socket *socket, byte *dest, uint64 numBytes) {
  243. int64 bytesRead = read((uint64)socket->handle, dest, numBytes);
  244. if (bytesRead == -1) {
  245. // TODO(dledda): handle err
  246. }
  247. return bytesRead;
  248. }
  249. StringResult socketReadStr(Arena *arena, Socket *socket) {
  250. byte *dest = PushArray(arena, byte, Kilobytes(256));
  251. int64 bytesRead = read((uint64)socket->handle, dest, Kilobytes(1024));
  252. bool err = bytesRead == -1 || bytesRead == 0;
  253. if (err) {
  254. arenaPopTo(arena, dest);
  255. } else {
  256. arenaPopTo(arena, dest + bytesRead);
  257. }
  258. return (StringResult){
  259. .valid=!err,
  260. .result=(string){
  261. .str=dest,
  262. .length=err ? 0 : bytesRead,
  263. },
  264. };
  265. }
  266. void serverClose(Server *s) {
  267. close((int)(uint64)s->handle);
  268. }
  269. bool serverHangupClient(Server *s, Socket *client) {
  270. struct epoll_event eventUnsubscribe = {
  271. .data.fd=(int)(int64)client->handle,
  272. .events=EPOLLIN | EPOLLET,
  273. };
  274. int err = epoll_ctl(((EPollServerEvents *)s->events)->epollFd, EPOLL_CTL_DEL, (int)(int64)client->handle, &eventUnsubscribe);
  275. if (err == 0) {
  276. for (EachIn(s->clients, i)) {
  277. if (s->clients.data[i].handle == client->handle) {
  278. ListRemove(&s->clients, i);
  279. return true;
  280. }
  281. }
  282. }
  283. return false;
  284. }
  285. void socketClose(Socket *s) {
  286. close((int)(uint64)s->handle);
  287. }
  288. Socket socketConnect(Arena *arena, SocketConnectInfo info) {
  289. int socketFd = socket(AF_INET6, SOCK_STREAM, 0 /* IPPROTO_TCP */);
  290. if (!info.blocking) {
  291. fcntl(socketFd, F_SETFL, fcntl(socketFd, F_GETFL, 0) | O_NONBLOCK);
  292. }
  293. struct sockaddr_in6 *remoteAddr = PushStructZero(arena, struct sockaddr_in6);
  294. remoteAddr->sin6_family = AF_INET6;
  295. inet_pton(AF_INET6, cstring(arena, info.address), &remoteAddr->sin6_addr);
  296. remoteAddr->sin6_port = htons(info.port);
  297. int connectErr = connect(socketFd, (struct sockaddr *)remoteAddr, sizeof(*remoteAddr));
  298. Socket result = {
  299. .handle=(SocketHandle *)(uint64)socketFd,
  300. .address=(Address *)remoteAddr,
  301. .closed=false,
  302. //.closed=connectErr == -1,
  303. // TODO(dledda): investigate error behaviour
  304. };
  305. return result;
  306. }
  307. int64 socketWrite(Socket *socket, byte *source, uint64 numBytes) {
  308. int64 written = send((uint64)socket->handle, source, numBytes, MSG_NOSIGNAL);
  309. if (written == -1) socket->closed = true;
  310. return written;
  311. }
  312. int64 socketWriteStr(Socket *socket, string data) {
  313. int64 written = send((uint64)socket->handle, data.str, data.length, MSG_NOSIGNAL);
  314. if (written == -1) socket->closed = true;
  315. return written;
  316. }
  317. #endif