Standard setup for writing C inspired by Casey Muratori, Ryan Fleury, Mr. 4th Programmer, and others in the handmade community.
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 

378 行
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