Standard setup for writing C inspired by Casey Muratori, Ryan Fleury, Mr. 4th Programmer, and others in the handmade community.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

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