The Pedigree Project 0.1
sys_arch.cc
1/*
2 * Copyright (c) 2008-2014, Pedigree Developers
3 *
4 * Please see the CONTRIB file in the root of the source tree for a full
5 * list of contributors.
6 *
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
10 *
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18 */
19
20#include <lwip/arch/sys_arch.h>
21#include <lwip/err.h>
22#include <lwip/errno.h>
23#include <lwip/sys.h>
24#include <pedigree/kernel/Log.h>
25#include <pedigree/kernel/panic.h>
26#include <pedigree/kernel/process/Mutex.h>
27#include <pedigree/kernel/process/Semaphore.h>
28#include <pedigree/kernel/process/Thread.h>
29#include <pedigree/kernel/processor/Processor.h>
30#include <pedigree/kernel/utilities/Mailbox.h>
31#include <pedigree/kernel/utilities/SecureRandom.h>
32#include <pedigree/kernel/utilities/pocketknife.h>
33
34#if UTILITY_LINUX
35#include <errno.h>
36#include <thread>
37#include <time.h>
38#include <unistd.h>
39
40static Spinlock g_Protection(false);
41#else
42// errno for lwIP usage, this is not ideal as it'll be exposed to ALL modules.
43int errno;
44#endif
45
47 pedigree_mbox() : buffer(64) {}
48
50 Buffer buffer;
51};
52
53void sys_init() {}
54
55static bool dns_random_bytes(void* buffer, size_t length) {
56#if UTILITY_LINUX
57 return getentropy(buffer, length) == 0;
58#else
59 return secure_random_bytes(buffer, length) == length;
60#endif
61}
62
63extern "C" int pedigree_dns_random_ready(void) {
64 uint8_t scratch = 0;
65 const bool ready = dns_random_bytes(&scratch, sizeof(scratch));
66 pedigree_random::erase(&scratch, sizeof(scratch));
67 return ready;
68}
69
70extern "C" uint32_t pedigree_dns_random(void) {
71 uint32_t result = 0;
72 // DNS admits requests only after seeding, and readiness cannot be revoked.
73 if (!dns_random_bytes(&result, sizeof(result)))
74 panic("DNS random generator unavailable after request admission");
75 return result;
76}
77
78u32_t sys_now() {
79#if UTILITY_LINUX
80 struct timespec spec;
81 clock_gettime(CLOCK_REALTIME, &spec);
82
83 return (spec.tv_sec * 1000) + (spec.tv_nsec / 1000000);
84#else
85 return Time::getTimeNanoseconds() / Time::Multiplier::Millisecond;
86#endif
87}
88
90 lwip_thread_fn thread;
91 void* arg;
92 char name[64];
93};
94
95static int thread_shim(void* arg) {
96 struct thread_meta* meta = static_cast<struct thread_meta*>(arg);
97 lwip_thread_fn thread = meta->thread;
98 void* threadArg = meta->arg;
99 delete meta;
100 thread(threadArg);
101 return 0;
102}
103
104sys_thread_t sys_thread_new(const char* name, lwip_thread_fn thread, void* arg, int stacksize,
105 int prio) {
107 auto meta = new struct thread_meta;
108 meta->thread = thread;
109 meta->arg = arg;
110 StringCopy(meta->name, name);
111 return pocketknife::runConcurrentlyAttached(thread_shim, meta);
112}
113
114int sys_thread_join(sys_thread_t thread) {
115 if (!thread) {
116 return 1;
117 }
118#if UTILITY_LINUX
119 pocketknife::attachTo(thread);
120 return 1;
121#else
122 return pocketknife::attachToForCompletion(thread) ? 1 : 0;
123#endif
124}
125
126int sys_thread_is_current(sys_thread_t thread) {
127 if (!thread) {
128 return 0;
129 }
130#if UTILITY_LINUX
131 std::thread* candidate = reinterpret_cast<std::thread*>(thread);
132 return candidate->get_id() == std::this_thread::get_id() ? 1 : 0;
133#else
134 return reinterpret_cast<Thread*>(thread) == Processor::information().getCurrentThread() ? 1 : 0;
135#endif
136}
137
138err_t sys_sem_new(sys_sem_t* sem, u8_t count) {
139#if UTILITY_LINUX
140 if (sem_init(sem, 0, count) != 0) {
141 return ERR_ARG;
142 } else {
143 return ERR_OK;
144 }
145#else
146 Semaphore* newsem = new Semaphore(count);
147 *sem = reinterpret_cast<void*>(newsem);
148 return ERR_OK;
149#endif
150}
151
152void sys_sem_free(sys_sem_t* sem) {
153#if UTILITY_LINUX
154 sem_destroy(sem);
155#else
156 Semaphore* s = reinterpret_cast<Semaphore*>(*sem);
157 delete s;
158 *sem = nullptr;
159#endif
160}
161
162int sys_sem_valid(sys_sem_t* sem) {
163#if UTILITY_LINUX
164 return 1;
165#else
166 if (*sem) {
167 return 1;
168 } else {
169 return 0;
170 }
171#endif
172}
173
174void sys_sem_set_invalid(sys_sem_t* sem) {
175#if !UTILITY_LINUX
176 *sem = nullptr;
177#endif
178}
179
180void sys_sem_signal(sys_sem_t* sem) {
181#if UTILITY_LINUX
182 sem_post(sem);
183#else
184 Semaphore* s = reinterpret_cast<Semaphore*>(*sem);
185 s->release();
186#endif
187}
188
189u32_t sys_arch_sem_wait(sys_sem_t* sem, u32_t timeout) {
190#if UTILITY_LINUX
191 struct timespec started = {};
192 clock_gettime(CLOCK_MONOTONIC, &started);
193
194 int result = 0;
195 if (timeout) {
196 struct timespec deadline = {};
197 clock_gettime(CLOCK_REALTIME, &deadline);
198 deadline.tv_sec += timeout / 1000;
199 deadline.tv_nsec += (timeout % 1000) * 1000000;
200 if (deadline.tv_nsec >= 1000000000) {
201 ++deadline.tv_sec;
202 deadline.tv_nsec -= 1000000000;
203 }
204
205#ifdef __APPLE__
206 // TODO: this is very wrong, it's a HACK
207 result = sem_wait(sem);
208#else
209 do {
210 result = sem_timedwait(sem, &deadline);
211 } while (result == -1 && errno == EINTR);
212#endif
213 } else {
214 do {
215 result = sem_wait(sem);
216 } while (result == -1 && errno == EINTR);
217 }
218
219 if (result == 0) {
220 struct timespec completed = {};
221 clock_gettime(CLOCK_MONOTONIC, &completed);
222 const uint64_t startedNs =
223 (static_cast<uint64_t>(started.tv_sec) * 1000000000ULL) + started.tv_nsec;
224 const uint64_t completedNs =
225 (static_cast<uint64_t>(completed.tv_sec) * 1000000000ULL) + completed.tv_nsec;
226 return (completedNs - startedNs) / 1000000ULL;
227 }
228
229 return SYS_ARCH_TIMEOUT;
230#else
231 const Time::Timestamp begin = Time::getTicks();
232
233 Semaphore* s = reinterpret_cast<Semaphore*>(*sem);
234 const size_t timeoutSecs = timeout / 1000;
235 const size_t timeoutUsecs = (timeout % 1000) * 1000;
236
237 // lwIP has no interrupted-semaphore result, and many callers keep a
238 // stack-owned request alive until this wait completes. Defer a signal to
239 // the surrounding syscall boundary instead of misreporting it as timeout
240 // and abandoning that request.
241 if (!s->acquireForCompletion(1, timeoutSecs, timeoutUsecs)) {
242 return SYS_ARCH_TIMEOUT;
243 }
244
245 const Time::Timestamp end = Time::getTicks();
246 return (end - begin) / Time::Multiplier::Millisecond;
247#endif
248}
249
250err_t sys_mbox_new(sys_mbox_t* mbox, int size) {
251 *mbox = new pedigree_mbox;
252 return ERR_OK;
253}
254
256 pedigree_mbox* mailbox = *mbox;
257 if (!mailbox) {
258 return;
259 }
260
261 mailbox->buffer.close();
262 delete mailbox;
263 *mbox = nullptr;
264}
265
266void sys_mbox_post(sys_mbox_t* mbox, void* msg) {
267 if ((*mbox)->buffer.write(msg) != pedigree_mbox::Buffer::NoError) {
268 FATAL("sys_mbox_post failed");
269 }
270}
271
273 if (!mbox || !*mbox) {
274 return ERR_ARG;
275 }
276 return (*mbox)->buffer.closeWritesWithFinal(msg) ? ERR_OK : ERR_CLSD;
277}
278
279u32_t sys_arch_mbox_tryfetch(sys_mbox_t* mbox, void** msg) {
280 void* value = nullptr;
281 pedigree_mbox::Buffer::Error error = pedigree_mbox::Buffer::NoError;
282 if (!(*mbox)->buffer.read(value, error)) {
283 return SYS_MBOX_EMPTY;
284 }
285
286 *msg = value;
287 return 0;
288}
289
290u32_t sys_arch_mbox_fetch(sys_mbox_t* mbox, void** msg, u32_t timeout) {
291 Time::Timestamp begin = Time::getTimeNanoseconds();
292
293 Time::Timestamp timeoutMs = 0;
294 if (timeout == 0) {
295 timeoutMs = Time::Infinity;
296 } else {
297 timeoutMs = timeout * Time::Multiplier::Millisecond;
298 }
299
300 void* value = nullptr;
301 pedigree_mbox::Buffer::Error error = pedigree_mbox::Buffer::NoError;
302 if (!(*mbox)->buffer.read(value, timeoutMs, error)) {
303 // TODO: check the specific error
304 return SYS_ARCH_TIMEOUT;
305 }
306
307 *msg = value;
308
309 Time::Timestamp end = Time::getTimeNanoseconds();
310 return (end - begin) / Time::Multiplier::Millisecond;
311}
312
314#if THREADS
316 return ERR_WOULDBLOCK;
317 }
318#endif
319 // Wait for the mailbox mutex, but never for queue space. Treating brief
320 // lock contention as a full mailbox drops otherwise deliverable packets.
321 Time::Timestamp timeout = 0;
322 const pedigree_mbox::Buffer::Error error = (*mbox)->buffer.write(msg, timeout);
323 if (error == pedigree_mbox::Buffer::TimedOut) {
324 return ERR_WOULDBLOCK;
325 }
326
327 return error == pedigree_mbox::Buffer::NoError ? ERR_OK : ERR_BUF;
328}
329
331 return *mbox != nullptr ? 1 : 0;
332}
333
335 *mbox = nullptr;
336}
337
338err_t sys_mutex_new(sys_mutex_t* mutex) {
339 Mutex* m = new Mutex;
340 *mutex = m;
341 return ERR_OK;
342}
343
344void sys_mutex_lock(sys_mutex_t* mutex) {
345 Mutex* m = reinterpret_cast<Mutex*>(*mutex);
346 while (!m->acquire())
347 ;
348}
349
350void sys_mutex_unlock(sys_mutex_t* mutex) {
351 Mutex* m = reinterpret_cast<Mutex*>(*mutex);
352 m->release();
353}
354
355void sys_mutex_free(sys_mutex_t* mutex) {
356 Mutex* m = reinterpret_cast<Mutex*>(*mutex);
357 delete m;
358 *mutex = nullptr;
359}
360
361int sys_mutex_valid(sys_mutex_t* mutex) {
362 return *mutex != nullptr ? 1 : 0;
363}
364
365void sys_mutex_set_invalid(sys_mutex_t* mutex) {
366 *mutex = nullptr;
367}
368
369sys_prot_t sys_arch_protect() {
370#if UTILITY_LINUX
371 while (!g_Protection.acquire(true))
372 ;
373
374 return 0;
375#else
376 bool was = Processor::getInterrupts();
378 return was ? 1 : 0;
379#endif
380}
381
382void sys_arch_unprotect(sys_prot_t pval) {
383#if UTILITY_LINUX
384 g_Protection.release();
385#else
387#endif
388}
void close()
Definition Mailbox.h:114
Definition Mutex.h:56
static bool getInterrupts()
static ProcessorInformation & information()
static bool inDeviceHardIrq()
Definition Processor.h:581
static void setInterrupts(bool bEnable)
void release(size_t n=1)
Definition Semaphore.cc:549
MUST_USE_RESULT bool acquireForCompletion(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)
Definition Semaphore.cc:372
bool acquire(size_t n=1, size_t timeoutSecs=0, size_t timeoutUsecs=0)
Definition Semaphore.cc:355
s8_t err_t
Definition err.h:76
@ ERR_BUF
Definition err.h:86
@ ERR_OK
Definition err.h:82
@ ERR_CLSD
Definition err.h:113
@ ERR_ARG
Definition err.h:115
@ ERR_WOULDBLOCK
Definition err.h:96
void EXPORTED_PUBLIC panic(const char *msg) NORETURN
Definition panic.cc:118
void sys_mbox_set_invalid(sys_mbox_t *mbox)
Definition sys_arch.cc:334
u32_t sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
Definition sys_arch.cc:290
int sys_mbox_valid(sys_mbox_t *mbox)
Definition sys_arch.cc:330
void sys_mbox_post(sys_mbox_t *mbox, void *msg)
Definition sys_arch.cc:266
err_t sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
Definition sys_arch.cc:313
err_t sys_mbox_new(sys_mbox_t *mbox, int size)
Definition sys_arch.cc:250
void sys_mbox_free(sys_mbox_t *mbox)
Definition sys_arch.cc:255
u32_t sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
Definition sys_arch.cc:279
sys_thread_t sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio)
Definition sys_arch.cc:104
void sys_mutex_free(sys_mutex_t *mutex)
Definition sys_arch.cc:355
err_t sys_mutex_new(sys_mutex_t *mutex)
Definition sys_arch.cc:338
void sys_mutex_set_invalid(sys_mutex_t *mutex)
Definition sys_arch.cc:365
void sys_mutex_lock(sys_mutex_t *mutex)
Definition sys_arch.cc:344
void sys_mutex_unlock(sys_mutex_t *mutex)
Definition sys_arch.cc:350
int sys_mutex_valid(sys_mutex_t *mutex)
Definition sys_arch.cc:361
int sys_sem_valid(sys_sem_t *sem)
Definition sys_arch.cc:162
void sys_sem_set_invalid(sys_sem_t *sem)
Definition sys_arch.cc:174
void sys_sem_free(sys_sem_t *sem)
Definition sys_arch.cc:152
u32_t sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
Definition sys_arch.cc:189
void sys_sem_signal(sys_sem_t *sem)
Definition sys_arch.cc:180
err_t sys_sem_new(sys_sem_t *sem, u8_t count)
Definition sys_arch.cc:138
u32_t sys_now()
Definition sys_arch.cc:78
EXPORTED_PUBLIC bool attachToForCompletion(void *handle)
EXPORTED_PUBLIC int attachTo(void *handle)
EXPORTED_PUBLIC void * runConcurrentlyAttached(int(*func)(void *), void *param)
int sys_thread_is_current(sys_thread_t thread)
Definition sys_arch.cc:126
int sys_thread_join(sys_thread_t thread)
Definition sys_arch.cc:114
#define SYS_MBOX_EMPTY
Definition sys.h:111
#define SYS_ARCH_TIMEOUT
Definition sys.h:106
void(* lwip_thread_fn)(void *arg)
Definition sys.h:117
err_t sys_mbox_post_and_close(sys_mbox_t *mbox, void *msg)
Definition sys_arch.cc:272