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