Threads and Scheduling
1#include "lib.h"
2#include "log.h"
3#include <stdlib.h>
4
5// Allocates new memory from src and returns a buffer to that memory. The user
6// must free that memory.
7Buffer bufcpy(Buffer src) {
8 Byte* buf = (Byte*)malloc(src.len * sizeof(Byte));
9 exists(buf);
10 memcpy(buf, src.buf, src.len);
11 return (Buffer){
12 .buf = buf,
13 .len = src.len,
14 };
15}
16
17// Checks whether the buffer contains a valid string and that the size provided
18// matches the size of that string.
19Buffer validate_str(Buffer str, size_t max_len) {
20 size_t calculated_len = safe_strlen((const char*)str.buf, max_len);
21 if (str.len != calculated_len) {
22 log(ERROR, "%s:%d String's length (%zu) is not equal to given length (%zu).", __FILE__, __LINE__, calculated_len, str.len);
23
24 printf("\nBuffer contains: ");
25 for (size_t i = 0; i < max_len; ++i) printf("[%d] ", str.buf[i]);
26 printf("\n");
27
28 exit(1);
29 }
30 if (str.len > max_len) {
31 log(ERROR, "%s:%d String's length (%zu) is larger than the buffer that contains it (%zu).\n", str.len, calculated_len);
32
33 printf("\nBuffer contains: ");
34 for (size_t i = 0; i < max_len; ++i) printf("[%d] ", str.buf[i]);
35 printf("\n");
36
37 exit(1);
38 }
39 return str;
40}
41
42// Converts the buffer received from a socket into an array of processes. The
43// user must free this memory.
44Procs deserialize(Buffer out_buf, size_t msg_len) {
45 Procs procs = {
46 .procs = (Proc*)calloc(1, sizeof(Proc)),
47 .len = 1,
48 };
49 exists(procs.procs);
50
51 // This loop will continue until all Proc's have been deserialized.
52 size_t buf_idx = 0;
53 for (size_t j = 0; buf_idx < msg_len; ++j) {
54 // Reallocate new Proc if more than one proc was received.
55 if (j == procs.len) {
56 procs.procs = (Proc*)realloc(procs.procs, procs.len + 1);
57 procs.len = procs.len + 1;
58 }
59
60 // curr represents the first byte where the Proc lives in the message.
61 Byte* curr = out_buf.buf + buf_idx;
62
63 // Parse out the data members.
64 Time time = *(Time*)curr;
65 size_t len = *(size_t*)(curr + sizeof(Time));
66 Byte* str_buf = curr + sizeof(Time) + sizeof(size_t);
67
68 // Validate the string in the buffer.
69 Buffer program = validate_str((Buffer){.len = len, .buf = str_buf}, msg_len - buf_idx);
70
71 // Insert everything into the proc list.
72 procs.procs[j] = (Proc){
73 .time = time,
74 .program = bufcpy(program),
75 };
76
77 // This calculates where the next Proc will be.
78 buf_idx += sizeof(Time) + sizeof(size_t) + program.len + 1;
79 }
80 return procs;
81}
82
83// This function turns a proc into a buffer. In order to do that, this function
84// reinterprets everything on the proc as a sequence of bytes.
85Buffer serialize(Proc proc) {
86 // First, determine how long the buffer has to be.
87 size_t len = sizeof(Time) + sizeof(size_t) + proc.program.len + 1;
88
89 // Allocate the bytes in the buffer.
90 Buffer buf = {
91 .len = len,
92 .buf = (Byte*)calloc(len, sizeof(Byte)),
93 };
94 exists(buf.buf);
95
96 // Copy everything in the buffer.
97 memcpy((void*)buf.buf, (void*)&proc.time, sizeof(Time));
98 memcpy((void*)(buf.buf + sizeof(Time)), (void*)&proc.program.len, sizeof(size_t));
99 memcpy((void*)(buf.buf + sizeof(Time) + sizeof(size_t)), (void*)proc.program.buf, proc.program.len);
100 return buf;
101}
102
103// This function takes a string representing an IPv4 address and converts it
104// into an IPv4 type.
105IPv4 parse_address(const char* str) {
106 size_t len = safe_strlen(str, 15);
107
108 IPv4 ip = {0};
109 size_t curr_byte = 0;
110 for (size_t i = 0; i < len; ++i) {
111 if (str[i] == '.') {
112 ++curr_byte;
113 } else {
114 ip.bytes[curr_byte] = (Byte)(ip.bytes[curr_byte] * 10 + (str[i] - '0'));
115 }
116 }
117
118 return ip;
119}
120
121// uses memchr to calculate strlen.
122size_t safe_strlen(const char* str, size_t max_len) {
123 return (size_t)memchr(str, '\0', max_len) - (size_t)str;
124}