e6a79782db0bf974da058a166cab13c616ad7882
[reactos.git] / reactos / lib / drivers / lwip / src / sys_arch.c
1 #include "lwip/sys.h"
2
3 #include "lwip/tcp.h"
4 #include "lwip/pbuf.h"
5 #include "lwip/err.h"
6
7 #include "rosip.h"
8
9 #include <debug.h>
10
11 static LIST_ENTRY ThreadListHead;
12 static KSPIN_LOCK ThreadListLock;
13
14 KEVENT TerminationEvent;
15 NPAGED_LOOKASIDE_LIST MessageLookasideList;
16 NPAGED_LOOKASIDE_LIST QueueEntryLookasideList;
17
18 static LARGE_INTEGER StartTime;
19
20 typedef struct _thread_t
21 {
22 HANDLE Handle;
23 void (* ThreadFunction)(void *arg);
24 void *ThreadContext;
25 LIST_ENTRY ListEntry;
26 } *thread_t;
27
28 u32_t sys_now(void)
29 {
30 LARGE_INTEGER CurrentTime;
31
32 KeQuerySystemTime(&CurrentTime);
33
34 return (CurrentTime.QuadPart - StartTime.QuadPart) / 10000;
35 }
36
37 void
38 sys_arch_protect(sys_prot_t *lev)
39 {
40 /* Preempt the dispatcher */
41 KeRaiseIrql(DISPATCH_LEVEL, lev);
42 }
43
44 void
45 sys_arch_unprotect(sys_prot_t lev)
46 {
47 KeLowerIrql(lev);
48 }
49
50 err_t
51 sys_sem_new(sys_sem_t *sem, u8_t count)
52 {
53 ASSERT(count == 0 || count == 1);
54
55 /* It seems lwIP uses the semaphore implementation as either a completion event or a lock
56 * so I optimize for this case by using a synchronization event and setting its initial state
57 * to signalled for a lock and non-signalled for a completion event */
58
59 KeInitializeEvent(&sem->Event, SynchronizationEvent, count);
60
61 sem->Valid = 1;
62
63 return ERR_OK;
64 }
65
66 int sys_sem_valid(sys_sem_t *sem)
67 {
68 return sem->Valid;
69 }
70
71 void sys_sem_set_invalid(sys_sem_t *sem)
72 {
73 sem->Valid = 0;
74 }
75
76 void
77 sys_sem_free(sys_sem_t* sem)
78 {
79 /* No op (allocated in stack) */
80
81 sys_sem_set_invalid(sem);
82 }
83
84 void
85 sys_sem_signal(sys_sem_t* sem)
86 {
87 KeSetEvent(&sem->Event, IO_NO_INCREMENT, FALSE);
88 }
89
90 u32_t
91 sys_arch_sem_wait(sys_sem_t* sem, u32_t timeout)
92 {
93 LARGE_INTEGER LargeTimeout, PreWaitTime, PostWaitTime;
94 UINT64 TimeDiff;
95 NTSTATUS Status;
96 PVOID WaitObjects[] = {&sem->Event, &TerminationEvent};
97
98 LargeTimeout.QuadPart = Int32x32To64(timeout, -10000);
99
100 KeQuerySystemTime(&PreWaitTime);
101
102 Status = KeWaitForMultipleObjects(2,
103 WaitObjects,
104 WaitAny,
105 Executive,
106 KernelMode,
107 FALSE,
108 timeout != 0 ? &LargeTimeout : NULL,
109 NULL);
110 if (Status == STATUS_WAIT_0)
111 {
112 KeQuerySystemTime(&PostWaitTime);
113 TimeDiff = PostWaitTime.QuadPart - PreWaitTime.QuadPart;
114 TimeDiff /= 10000;
115
116 return TimeDiff;
117 }
118 else if (Status == STATUS_WAIT_1)
119 {
120 /* DON'T remove ourselves from the thread list! */
121 PsTerminateSystemThread(STATUS_SUCCESS);
122
123 /* We should never get here! */
124 ASSERT(FALSE);
125
126 return 0;
127 }
128
129 return SYS_ARCH_TIMEOUT;
130 }
131
132 err_t
133 sys_mbox_new(sys_mbox_t *mbox, int size)
134 {
135 KeInitializeSpinLock(&mbox->Lock);
136
137 InitializeListHead(&mbox->ListHead);
138
139 KeInitializeEvent(&mbox->Event, NotificationEvent, FALSE);
140
141 mbox->Valid = 1;
142
143 return ERR_OK;
144 }
145
146 int sys_mbox_valid(sys_mbox_t *mbox)
147 {
148 return mbox->Valid;
149 }
150
151 void sys_mbox_set_invalid(sys_mbox_t *mbox)
152 {
153 mbox->Valid = 0;
154 }
155
156 void
157 sys_mbox_free(sys_mbox_t *mbox)
158 {
159 ASSERT(IsListEmpty(&mbox->ListHead));
160
161 sys_mbox_set_invalid(mbox);
162 }
163
164 void
165 sys_mbox_post(sys_mbox_t *mbox, void *msg)
166 {
167 PLWIP_MESSAGE_CONTAINER Container;
168
169 Container = ExAllocatePool(NonPagedPool, sizeof(*Container));
170 ASSERT(Container);
171
172 Container->Message = msg;
173
174 ExInterlockedInsertTailList(&mbox->ListHead,
175 &Container->ListEntry,
176 &mbox->Lock);
177
178 KeSetEvent(&mbox->Event, IO_NO_INCREMENT, FALSE);
179 }
180
181 u32_t
182 sys_arch_mbox_fetch(sys_mbox_t *mbox, void **msg, u32_t timeout)
183 {
184 LARGE_INTEGER LargeTimeout, PreWaitTime, PostWaitTime;
185 UINT64 TimeDiff;
186 NTSTATUS Status;
187 PVOID Message;
188 PLWIP_MESSAGE_CONTAINER Container;
189 PLIST_ENTRY Entry;
190 KIRQL OldIrql;
191 PVOID WaitObjects[] = {&mbox->Event, &TerminationEvent};
192
193 LargeTimeout.QuadPart = Int32x32To64(timeout, -10000);
194
195 KeQuerySystemTime(&PreWaitTime);
196
197 Status = KeWaitForMultipleObjects(2,
198 WaitObjects,
199 WaitAny,
200 Executive,
201 KernelMode,
202 FALSE,
203 timeout != 0 ? &LargeTimeout : NULL,
204 NULL);
205
206 if (Status == STATUS_WAIT_0)
207 {
208 KeAcquireSpinLock(&mbox->Lock, &OldIrql);
209 Entry = RemoveHeadList(&mbox->ListHead);
210 ASSERT(Entry);
211 if (IsListEmpty(&mbox->ListHead))
212 KeClearEvent(&mbox->Event);
213 KeReleaseSpinLock(&mbox->Lock, OldIrql);
214
215 Container = CONTAINING_RECORD(Entry, LWIP_MESSAGE_CONTAINER, ListEntry);
216 Message = Container->Message;
217 ExFreePool(Container);
218
219 if (msg)
220 *msg = Message;
221
222 KeQuerySystemTime(&PostWaitTime);
223 TimeDiff = PostWaitTime.QuadPart - PreWaitTime.QuadPart;
224 TimeDiff /= 10000;
225
226 return TimeDiff;
227 }
228 else if (Status == STATUS_WAIT_1)
229 {
230 /* DON'T remove ourselves from the thread list! */
231 PsTerminateSystemThread(STATUS_SUCCESS);
232
233 /* We should never get here! */
234 ASSERT(FALSE);
235
236 return 0;
237 }
238
239 return SYS_ARCH_TIMEOUT;
240 }
241
242 u32_t
243 sys_arch_mbox_tryfetch(sys_mbox_t *mbox, void **msg)
244 {
245 if (sys_arch_mbox_fetch(mbox, msg, 1) != SYS_ARCH_TIMEOUT)
246 return 0;
247 else
248 return SYS_MBOX_EMPTY;
249 }
250
251 err_t
252 sys_mbox_trypost(sys_mbox_t *mbox, void *msg)
253 {
254 sys_mbox_post(mbox, msg);
255
256 return ERR_OK;
257 }
258
259 VOID
260 NTAPI
261 LwipThreadMain(PVOID Context)
262 {
263 thread_t Container = (thread_t)Context;
264 KIRQL OldIrql;
265
266 ExInterlockedInsertHeadList(&ThreadListHead, &Container->ListEntry, &ThreadListLock);
267
268 Container->ThreadFunction(Container->ThreadContext);
269
270 KeAcquireSpinLock(&ThreadListLock, &OldIrql);
271 RemoveEntryList(&Container->ListEntry);
272 KeReleaseSpinLock(&ThreadListLock, OldIrql);
273
274 ExFreePool(Container);
275
276 PsTerminateSystemThread(STATUS_SUCCESS);
277 }
278
279 sys_thread_t
280 sys_thread_new(const char *name, lwip_thread_fn thread, void *arg, int stacksize, int prio)
281 {
282 thread_t Container;
283 NTSTATUS Status;
284
285 Container = ExAllocatePool(NonPagedPool, sizeof(*Container));
286 if (!Container)
287 return 0;
288
289 Container->ThreadFunction = thread;
290 Container->ThreadContext = arg;
291
292 Status = PsCreateSystemThread(&Container->Handle,
293 THREAD_ALL_ACCESS,
294 NULL,
295 NULL,
296 NULL,
297 LwipThreadMain,
298 Container);
299
300 if (!NT_SUCCESS(Status))
301 {
302 ExFreePool(Container);
303 return 0;
304 }
305
306 return 0;
307 }
308
309 void
310 sys_init(void)
311 {
312 KeInitializeSpinLock(&ThreadListLock);
313 InitializeListHead(&ThreadListHead);
314
315 KeQuerySystemTime(&StartTime);
316
317 KeInitializeEvent(&TerminationEvent, NotificationEvent, FALSE);
318
319 ExInitializeNPagedLookasideList(&MessageLookasideList,
320 NULL,
321 NULL,
322 0,
323 sizeof(struct lwip_callback_msg),
324 LWIP_TAG,
325 0);
326
327 ExInitializeNPagedLookasideList(&QueueEntryLookasideList,
328 NULL,
329 NULL,
330 0,
331 sizeof(QUEUE_ENTRY),
332 LWIP_TAG,
333 0);
334 }
335
336 void
337 sys_shutdown(void)
338 {
339 PLIST_ENTRY CurrentEntry;
340 thread_t Container;
341
342 /* Set the termination event */
343 KeSetEvent(&TerminationEvent, IO_NO_INCREMENT, FALSE);
344
345 /* Loop through the thread list and wait for each to die */
346 while ((CurrentEntry = ExInterlockedRemoveHeadList(&ThreadListHead, &ThreadListLock)))
347 {
348 Container = CONTAINING_RECORD(CurrentEntry, struct _thread_t, ListEntry);
349
350 if (Container->ThreadFunction)
351 {
352 KeWaitForSingleObject(Container->Handle,
353 Executive,
354 KernelMode,
355 FALSE,
356 NULL);
357
358 ZwClose(Container->Handle);
359 }
360 }
361
362 ExDeleteNPagedLookasideList(&MessageLookasideList);
363 ExDeleteNPagedLookasideList(&QueueEntryLookasideList);
364 }