[457] | 1 | /*
|
---|
| 2 | * Copyright (c) 2001-2003 Swedish Institute of Computer Science.
|
---|
| 3 | * All rights reserved.
|
---|
| 4 | *
|
---|
| 5 | * Redistribution and use in source and binary forms, with or without modification,
|
---|
| 6 | * are permitted provided that the following conditions are met:
|
---|
| 7 | *
|
---|
| 8 | * 1. Redistributions of source code must retain the above copyright notice,
|
---|
| 9 | * this list of conditions and the following disclaimer.
|
---|
| 10 | * 2. Redistributions in binary form must reproduce the above copyright notice,
|
---|
| 11 | * this list of conditions and the following disclaimer in the documentation
|
---|
| 12 | * and/or other materials provided with the distribution.
|
---|
| 13 | * 3. The name of the author may not be used to endorse or promote products
|
---|
| 14 | * derived from this software without specific prior written permission.
|
---|
| 15 | *
|
---|
| 16 | * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
---|
| 17 | * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
---|
| 18 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
---|
| 19 | * SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
|
---|
| 20 | * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
|
---|
| 21 | * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
---|
| 22 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
---|
| 23 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
|
---|
| 24 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
---|
| 25 | * OF SUCH DAMAGE.
|
---|
| 26 | *
|
---|
| 27 | * This file is part of the lwIP TCP/IP stack.
|
---|
| 28 | *
|
---|
| 29 | * Author: Adam Dunkels <adam@sics.se>
|
---|
| 30 | * Simon Goldschmidt
|
---|
| 31 | *
|
---|
| 32 | */
|
---|
| 33 |
|
---|
| 34 | #include <stdlib.h>
|
---|
| 35 | #include <stdio.h> /* sprintf() for task names */
|
---|
| 36 |
|
---|
| 37 | #ifdef _MSC_VER
|
---|
| 38 | #pragma warning (push, 3)
|
---|
| 39 | #endif
|
---|
| 40 | #include <windows.h>
|
---|
| 41 | #ifdef _MSC_VER
|
---|
| 42 | #pragma warning (pop)
|
---|
| 43 | #endif
|
---|
| 44 | #include <time.h>
|
---|
| 45 |
|
---|
| 46 | #include <lwip/opt.h>
|
---|
| 47 | #include <lwip/arch.h>
|
---|
| 48 | #include <lwip/stats.h>
|
---|
| 49 | #include <lwip/debug.h>
|
---|
| 50 | #include <lwip/sys.h>
|
---|
| 51 | #include <lwip/tcpip.h>
|
---|
| 52 |
|
---|
| 53 | /** Set this to 1 to enable assertion checks that SYS_ARCH_PROTECT() is only
|
---|
| 54 | * called once in a call stack (calling it nested might cause trouble in some
|
---|
| 55 | * implementations, so let's avoid this in core code as long as we can).
|
---|
| 56 | */
|
---|
| 57 | #ifndef LWIP_SYS_ARCH_CHECK_NESTED_PROTECT
|
---|
| 58 | #define LWIP_SYS_ARCH_CHECK_NESTED_PROTECT 1
|
---|
| 59 | #endif
|
---|
| 60 |
|
---|
| 61 | /** Set this to 1 to enable assertion checks that SYS_ARCH_PROTECT() is *not*
|
---|
| 62 | * called before functions potentiolly involving the OS scheduler.
|
---|
| 63 | *
|
---|
| 64 | * This scheme is currently broken only for non-core-locking when waking up
|
---|
| 65 | * threads waiting on a socket via select/poll.
|
---|
| 66 | */
|
---|
| 67 | #ifndef LWIP_SYS_ARCH_CHECK_SCHEDULING_UNPROTECTED
|
---|
| 68 | #define LWIP_SYS_ARCH_CHECK_SCHEDULING_UNPROTECTED LWIP_TCPIP_CORE_LOCKING
|
---|
| 69 | #endif
|
---|
| 70 |
|
---|
| 71 | #define LWIP_WIN32_SYS_ARCH_ENABLE_PROTECT_COUNTER (LWIP_SYS_ARCH_CHECK_NESTED_PROTECT || LWIP_SYS_ARCH_CHECK_SCHEDULING_UNPROTECTED)
|
---|
| 72 |
|
---|
| 73 | /* These functions are used from NO_SYS also, for precise timer triggering */
|
---|
| 74 | static LARGE_INTEGER freq, sys_start_time;
|
---|
| 75 | #define SYS_INITIALIZED() (freq.QuadPart != 0)
|
---|
| 76 |
|
---|
| 77 | static DWORD netconn_sem_tls_index;
|
---|
| 78 |
|
---|
| 79 | static HCRYPTPROV hcrypt;
|
---|
| 80 |
|
---|
| 81 | u32_t
|
---|
| 82 | sys_win_rand(void)
|
---|
| 83 | {
|
---|
| 84 | u32_t ret;
|
---|
| 85 | if (CryptGenRandom(hcrypt, sizeof(ret), (BYTE*)&ret)) {
|
---|
| 86 | return ret;
|
---|
| 87 | }
|
---|
| 88 | LWIP_ASSERT("CryptGenRandom failed", 0);
|
---|
| 89 | return 0;
|
---|
| 90 | }
|
---|
| 91 |
|
---|
| 92 | static void
|
---|
| 93 | sys_win_rand_init(void)
|
---|
| 94 | {
|
---|
| 95 | if (!CryptAcquireContext(&hcrypt, NULL, NULL, PROV_RSA_FULL, 0)) {
|
---|
| 96 | DWORD err = GetLastError();
|
---|
| 97 | LWIP_PLATFORM_DIAG(("CryptAcquireContext failed with error %d, trying to create NEWKEYSET", (int)err));
|
---|
| 98 | if(!CryptAcquireContext(&hcrypt, NULL, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)) {
|
---|
| 99 | char errbuf[128];
|
---|
| 100 | err = GetLastError();
|
---|
| 101 | snprintf(errbuf, sizeof(errbuf), "CryptAcquireContext failed with error %d", (int)err);
|
---|
| 102 | LWIP_UNUSED_ARG(err);
|
---|
| 103 | LWIP_ASSERT(errbuf, 0);
|
---|
| 104 | }
|
---|
| 105 | }
|
---|
| 106 | }
|
---|
| 107 |
|
---|
| 108 | static void
|
---|
| 109 | sys_init_timing(void)
|
---|
| 110 | {
|
---|
| 111 | QueryPerformanceFrequency(&freq);
|
---|
| 112 | QueryPerformanceCounter(&sys_start_time);
|
---|
| 113 | }
|
---|
| 114 |
|
---|
| 115 | static LONGLONG
|
---|
| 116 | sys_get_ms_longlong(void)
|
---|
| 117 | {
|
---|
| 118 | LONGLONG ret;
|
---|
| 119 | LARGE_INTEGER now;
|
---|
| 120 | #if NO_SYS
|
---|
| 121 | if (!SYS_INITIALIZED()) {
|
---|
| 122 | sys_init();
|
---|
| 123 | LWIP_ASSERT("initialization failed", SYS_INITIALIZED());
|
---|
| 124 | }
|
---|
| 125 | #endif /* NO_SYS */
|
---|
| 126 | QueryPerformanceCounter(&now);
|
---|
| 127 | ret = now.QuadPart-sys_start_time.QuadPart;
|
---|
| 128 | return (u32_t)(((ret)*1000)/freq.QuadPart);
|
---|
| 129 | }
|
---|
| 130 |
|
---|
| 131 | u32_t
|
---|
| 132 | sys_jiffies(void)
|
---|
| 133 | {
|
---|
| 134 | return (u32_t)sys_get_ms_longlong();
|
---|
| 135 | }
|
---|
| 136 |
|
---|
| 137 | u32_t
|
---|
| 138 | sys_now(void)
|
---|
| 139 | {
|
---|
| 140 | return (u32_t)sys_get_ms_longlong();
|
---|
| 141 | }
|
---|
| 142 |
|
---|
| 143 | CRITICAL_SECTION critSec;
|
---|
| 144 | #if LWIP_WIN32_SYS_ARCH_ENABLE_PROTECT_COUNTER
|
---|
| 145 | static int protection_depth;
|
---|
| 146 | #endif
|
---|
| 147 |
|
---|
| 148 | static void
|
---|
| 149 | InitSysArchProtect(void)
|
---|
| 150 | {
|
---|
| 151 | InitializeCriticalSection(&critSec);
|
---|
| 152 | }
|
---|
| 153 |
|
---|
| 154 | sys_prot_t
|
---|
| 155 | sys_arch_protect(void)
|
---|
| 156 | {
|
---|
| 157 | #if NO_SYS
|
---|
| 158 | if (!SYS_INITIALIZED()) {
|
---|
| 159 | sys_init();
|
---|
| 160 | LWIP_ASSERT("initialization failed", SYS_INITIALIZED());
|
---|
| 161 | }
|
---|
| 162 | #endif
|
---|
| 163 | EnterCriticalSection(&critSec);
|
---|
| 164 | #if LWIP_SYS_ARCH_CHECK_NESTED_PROTECT
|
---|
| 165 | LWIP_ASSERT("nested SYS_ARCH_PROTECT", protection_depth == 0);
|
---|
| 166 | #endif
|
---|
| 167 | #if LWIP_WIN32_SYS_ARCH_ENABLE_PROTECT_COUNTER
|
---|
| 168 | protection_depth++;
|
---|
| 169 | #endif
|
---|
| 170 | return 0;
|
---|
| 171 | }
|
---|
| 172 |
|
---|
| 173 | void
|
---|
| 174 | sys_arch_unprotect(sys_prot_t pval)
|
---|
| 175 | {
|
---|
| 176 | LWIP_UNUSED_ARG(pval);
|
---|
| 177 | #if LWIP_SYS_ARCH_CHECK_NESTED_PROTECT
|
---|
| 178 | LWIP_ASSERT("missing SYS_ARCH_PROTECT", protection_depth == 1);
|
---|
| 179 | #else
|
---|
| 180 | LWIP_ASSERT("missing SYS_ARCH_PROTECT", protection_depth > 0);
|
---|
| 181 | #endif
|
---|
| 182 | #if LWIP_WIN32_SYS_ARCH_ENABLE_PROTECT_COUNTER
|
---|
| 183 | protection_depth--;
|
---|
| 184 | #endif
|
---|
| 185 | LeaveCriticalSection(&critSec);
|
---|
| 186 | }
|
---|
| 187 |
|
---|
| 188 | #if LWIP_SYS_ARCH_CHECK_SCHEDULING_UNPROTECTED
|
---|
| 189 | /** This checks that SYS_ARCH_PROTECT() hasn't been called by protecting
|
---|
| 190 | * and then checking the level
|
---|
| 191 | */
|
---|
| 192 | static void
|
---|
| 193 | sys_arch_check_not_protected(void)
|
---|
| 194 | {
|
---|
| 195 | sys_arch_protect();
|
---|
| 196 | LWIP_ASSERT("SYS_ARCH_PROTECT before scheduling", protection_depth == 1);
|
---|
| 197 | sys_arch_unprotect(0);
|
---|
| 198 | }
|
---|
| 199 | #else
|
---|
| 200 | #define sys_arch_check_not_protected()
|
---|
| 201 | #endif
|
---|
| 202 |
|
---|
| 203 | static void
|
---|
| 204 | msvc_sys_init(void)
|
---|
| 205 | {
|
---|
| 206 | sys_win_rand_init();
|
---|
| 207 | sys_init_timing();
|
---|
| 208 | InitSysArchProtect();
|
---|
| 209 | netconn_sem_tls_index = TlsAlloc();
|
---|
| 210 | LWIP_ASSERT("TlsAlloc failed", netconn_sem_tls_index != TLS_OUT_OF_INDEXES);
|
---|
| 211 | }
|
---|
| 212 |
|
---|
| 213 | void
|
---|
| 214 | sys_init(void)
|
---|
| 215 | {
|
---|
| 216 | msvc_sys_init();
|
---|
| 217 | }
|
---|
| 218 |
|
---|
| 219 | #if !NO_SYS
|
---|
| 220 |
|
---|
| 221 | struct threadlist {
|
---|
| 222 | lwip_thread_fn function;
|
---|
| 223 | void *arg;
|
---|
| 224 | DWORD id;
|
---|
| 225 | struct threadlist *next;
|
---|
| 226 | };
|
---|
| 227 |
|
---|
| 228 | static struct threadlist *lwip_win32_threads = NULL;
|
---|
| 229 |
|
---|
| 230 | err_t
|
---|
| 231 | sys_sem_new(sys_sem_t *sem, u8_t count)
|
---|
| 232 | {
|
---|
| 233 | HANDLE new_sem = NULL;
|
---|
| 234 |
|
---|
| 235 | LWIP_ASSERT("sem != NULL", sem != NULL);
|
---|
| 236 |
|
---|
| 237 | new_sem = CreateSemaphore(0, count, 100000, 0);
|
---|
| 238 | LWIP_ASSERT("Error creating semaphore", new_sem != NULL);
|
---|
| 239 | if(new_sem != NULL) {
|
---|
| 240 | if (SYS_INITIALIZED()) {
|
---|
| 241 | SYS_ARCH_LOCKED(SYS_STATS_INC_USED(sem));
|
---|
| 242 | } else {
|
---|
| 243 | SYS_STATS_INC_USED(sem);
|
---|
| 244 | }
|
---|
| 245 | #if LWIP_STATS && SYS_STATS
|
---|
| 246 | LWIP_ASSERT("sys_sem_new() counter overflow", lwip_stats.sys.sem.used != 0);
|
---|
| 247 | #endif /* LWIP_STATS && SYS_STATS*/
|
---|
| 248 | sem->sem = new_sem;
|
---|
| 249 | return ERR_OK;
|
---|
| 250 | }
|
---|
| 251 |
|
---|
| 252 | /* failed to allocate memory... */
|
---|
| 253 | if (SYS_INITIALIZED()) {
|
---|
| 254 | SYS_ARCH_LOCKED(SYS_STATS_INC(sem.err));
|
---|
| 255 | } else {
|
---|
| 256 | SYS_STATS_INC(sem.err);
|
---|
| 257 | }
|
---|
| 258 | sem->sem = NULL;
|
---|
| 259 | return ERR_MEM;
|
---|
| 260 | }
|
---|
| 261 |
|
---|
| 262 | void
|
---|
| 263 | sys_sem_free(sys_sem_t *sem)
|
---|
| 264 | {
|
---|
| 265 | /* parameter check */
|
---|
| 266 | LWIP_ASSERT("sem != NULL", sem != NULL);
|
---|
| 267 | LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL);
|
---|
| 268 | LWIP_ASSERT("sem->sem != INVALID_HANDLE_VALUE", sem->sem != INVALID_HANDLE_VALUE);
|
---|
| 269 | CloseHandle(sem->sem);
|
---|
| 270 |
|
---|
| 271 | SYS_ARCH_LOCKED(SYS_STATS_DEC(sem.used));
|
---|
| 272 | #if LWIP_STATS && SYS_STATS
|
---|
| 273 | LWIP_ASSERT("sys_sem_free() closed more than created", lwip_stats.sys.sem.used != (u16_t)-1);
|
---|
| 274 | #endif /* LWIP_STATS && SYS_STATS */
|
---|
| 275 | sem->sem = NULL;
|
---|
| 276 | }
|
---|
| 277 |
|
---|
| 278 | u32_t
|
---|
| 279 | sys_arch_sem_wait(sys_sem_t *sem, u32_t timeout)
|
---|
| 280 | {
|
---|
| 281 | DWORD ret;
|
---|
| 282 | LONGLONG starttime, endtime;
|
---|
| 283 | LWIP_ASSERT("sem != NULL", sem != NULL);
|
---|
| 284 | LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL);
|
---|
| 285 | LWIP_ASSERT("sem->sem != INVALID_HANDLE_VALUE", sem->sem != INVALID_HANDLE_VALUE);
|
---|
| 286 | if (!timeout) {
|
---|
| 287 | /* wait infinite */
|
---|
| 288 | starttime = sys_get_ms_longlong();
|
---|
| 289 | ret = WaitForSingleObject(sem->sem, INFINITE);
|
---|
| 290 | LWIP_ASSERT("Error waiting for semaphore", ret == WAIT_OBJECT_0);
|
---|
| 291 | endtime = sys_get_ms_longlong();
|
---|
| 292 | /* return the time we waited for the sem */
|
---|
| 293 | return (u32_t)(endtime - starttime);
|
---|
| 294 | } else {
|
---|
| 295 | starttime = sys_get_ms_longlong();
|
---|
| 296 | ret = WaitForSingleObject(sem->sem, timeout);
|
---|
| 297 | LWIP_ASSERT("Error waiting for semaphore", (ret == WAIT_OBJECT_0) || (ret == WAIT_TIMEOUT));
|
---|
| 298 | if (ret == WAIT_OBJECT_0) {
|
---|
| 299 | endtime = sys_get_ms_longlong();
|
---|
| 300 | /* return the time we waited for the sem */
|
---|
| 301 | return (u32_t)(endtime - starttime);
|
---|
| 302 | } else {
|
---|
| 303 | /* timeout */
|
---|
| 304 | return SYS_ARCH_TIMEOUT;
|
---|
| 305 | }
|
---|
| 306 | }
|
---|
| 307 | }
|
---|
| 308 |
|
---|
| 309 | void
|
---|
| 310 | sys_sem_signal(sys_sem_t *sem)
|
---|
| 311 | {
|
---|
| 312 | BOOL ret;
|
---|
| 313 | sys_arch_check_not_protected();
|
---|
| 314 | LWIP_ASSERT("sem != NULL", sem != NULL);
|
---|
| 315 | LWIP_ASSERT("sem->sem != NULL", sem->sem != NULL);
|
---|
| 316 | LWIP_ASSERT("sem->sem != INVALID_HANDLE_VALUE", sem->sem != INVALID_HANDLE_VALUE);
|
---|
| 317 | ret = ReleaseSemaphore(sem->sem, 1, NULL);
|
---|
| 318 | LWIP_ASSERT("Error releasing semaphore", ret != 0);
|
---|
| 319 | LWIP_UNUSED_ARG(ret);
|
---|
| 320 | }
|
---|
| 321 |
|
---|
| 322 | err_t
|
---|
| 323 | sys_mutex_new(sys_mutex_t *mutex)
|
---|
| 324 | {
|
---|
| 325 | HANDLE new_mut = NULL;
|
---|
| 326 |
|
---|
| 327 | LWIP_ASSERT("mutex != NULL", mutex != NULL);
|
---|
| 328 |
|
---|
| 329 | new_mut = CreateMutex(NULL, FALSE, NULL);
|
---|
| 330 | LWIP_ASSERT("Error creating mutex", new_mut != NULL);
|
---|
| 331 | if (new_mut != NULL) {
|
---|
| 332 | SYS_ARCH_LOCKED(SYS_STATS_INC_USED(mutex));
|
---|
| 333 | #if LWIP_STATS && SYS_STATS
|
---|
| 334 | LWIP_ASSERT("sys_mutex_new() counter overflow", lwip_stats.sys.mutex.used != 0);
|
---|
| 335 | #endif /* LWIP_STATS && SYS_STATS*/
|
---|
| 336 | mutex->mut = new_mut;
|
---|
| 337 | return ERR_OK;
|
---|
| 338 | }
|
---|
| 339 |
|
---|
| 340 | /* failed to allocate memory... */
|
---|
| 341 | SYS_ARCH_LOCKED(SYS_STATS_INC(mutex.err));
|
---|
| 342 | mutex->mut = NULL;
|
---|
| 343 | return ERR_MEM;
|
---|
| 344 | }
|
---|
| 345 |
|
---|
| 346 | void
|
---|
| 347 | sys_mutex_free(sys_mutex_t *mutex)
|
---|
| 348 | {
|
---|
| 349 | /* parameter check */
|
---|
| 350 | LWIP_ASSERT("mutex != NULL", mutex != NULL);
|
---|
| 351 | LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL);
|
---|
| 352 | LWIP_ASSERT("mutex->mut != INVALID_HANDLE_VALUE", mutex->mut != INVALID_HANDLE_VALUE);
|
---|
| 353 | CloseHandle(mutex->mut);
|
---|
| 354 |
|
---|
| 355 | SYS_ARCH_LOCKED(SYS_STATS_DEC(mutex.used));
|
---|
| 356 | #if LWIP_STATS && SYS_STATS
|
---|
| 357 | LWIP_ASSERT("sys_mutex_free() closed more than created", lwip_stats.sys.mutex.used != (u16_t)-1);
|
---|
| 358 | #endif /* LWIP_STATS && SYS_STATS */
|
---|
| 359 | mutex->mut = NULL;
|
---|
| 360 | }
|
---|
| 361 |
|
---|
| 362 | void sys_mutex_lock(sys_mutex_t *mutex)
|
---|
| 363 | {
|
---|
| 364 | DWORD ret;
|
---|
| 365 | LWIP_ASSERT("mutex != NULL", mutex != NULL);
|
---|
| 366 | LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL);
|
---|
| 367 | LWIP_ASSERT("mutex->mut != INVALID_HANDLE_VALUE", mutex->mut != INVALID_HANDLE_VALUE);
|
---|
| 368 | /* wait infinite */
|
---|
| 369 | ret = WaitForSingleObject(mutex->mut, INFINITE);
|
---|
| 370 | LWIP_ASSERT("Error waiting for mutex", ret == WAIT_OBJECT_0);
|
---|
| 371 | LWIP_UNUSED_ARG(ret);
|
---|
| 372 | }
|
---|
| 373 |
|
---|
| 374 | void
|
---|
| 375 | sys_mutex_unlock(sys_mutex_t *mutex)
|
---|
| 376 | {
|
---|
| 377 | sys_arch_check_not_protected();
|
---|
| 378 | LWIP_ASSERT("mutex != NULL", mutex != NULL);
|
---|
| 379 | LWIP_ASSERT("mutex->mut != NULL", mutex->mut != NULL);
|
---|
| 380 | LWIP_ASSERT("mutex->mut != INVALID_HANDLE_VALUE", mutex->mut != INVALID_HANDLE_VALUE);
|
---|
| 381 | /* wait infinite */
|
---|
| 382 | if (!ReleaseMutex(mutex->mut)) {
|
---|
| 383 | LWIP_ASSERT("Error releasing mutex", 0);
|
---|
| 384 | }
|
---|
| 385 | }
|
---|
| 386 |
|
---|
| 387 |
|
---|
| 388 | #ifdef _MSC_VER
|
---|
| 389 | const DWORD MS_VC_EXCEPTION=0x406D1388;
|
---|
| 390 | #pragma pack(push,8)
|
---|
| 391 | typedef struct tagTHREADNAME_INFO
|
---|
| 392 | {
|
---|
| 393 | DWORD dwType; /* Must be 0x1000. */
|
---|
| 394 | LPCSTR szName; /* Pointer to name (in user addr space). */
|
---|
| 395 | DWORD dwThreadID; /* Thread ID (-1=caller thread). */
|
---|
| 396 | DWORD dwFlags; /* Reserved for future use, must be zero. */
|
---|
| 397 | } THREADNAME_INFO;
|
---|
| 398 | #pragma pack(pop)
|
---|
| 399 |
|
---|
| 400 | static void
|
---|
| 401 | SetThreadName(DWORD dwThreadID, const char* threadName)
|
---|
| 402 | {
|
---|
| 403 | THREADNAME_INFO info;
|
---|
| 404 | info.dwType = 0x1000;
|
---|
| 405 | info.szName = threadName;
|
---|
| 406 | info.dwThreadID = dwThreadID;
|
---|
| 407 | info.dwFlags = 0;
|
---|
| 408 |
|
---|
| 409 | __try {
|
---|
| 410 | RaiseException(MS_VC_EXCEPTION, 0, sizeof(info)/sizeof(ULONG_PTR), (ULONG_PTR*)&info);
|
---|
| 411 | }
|
---|
| 412 | __except(EXCEPTION_EXECUTE_HANDLER) {
|
---|
| 413 | }
|
---|
| 414 | }
|
---|
| 415 | #else /* _MSC_VER */
|
---|
| 416 | static void
|
---|
| 417 | SetThreadName(DWORD dwThreadID, const char* threadName)
|
---|
| 418 | {
|
---|
| 419 | LWIP_UNUSED_ARG(dwThreadID);
|
---|
| 420 | LWIP_UNUSED_ARG(threadName);
|
---|
| 421 | }
|
---|
| 422 | #endif /* _MSC_VER */
|
---|
| 423 |
|
---|
| 424 | static void
|
---|
| 425 | sys_thread_function(void* arg)
|
---|
| 426 | {
|
---|
| 427 | struct threadlist* t = (struct threadlist*)arg;
|
---|
| 428 | #if LWIP_NETCONN_SEM_PER_THREAD
|
---|
| 429 | sys_arch_netconn_sem_alloc();
|
---|
| 430 | #endif
|
---|
| 431 | t->function(t->arg);
|
---|
| 432 | #if LWIP_NETCONN_SEM_PER_THREAD
|
---|
| 433 | sys_arch_netconn_sem_free();
|
---|
| 434 | #endif
|
---|
| 435 | }
|
---|
| 436 |
|
---|
| 437 | sys_thread_t
|
---|
| 438 | sys_thread_new(const char *name, lwip_thread_fn function, void *arg, int stacksize, int prio)
|
---|
| 439 | {
|
---|
| 440 | struct threadlist *new_thread;
|
---|
| 441 | HANDLE h;
|
---|
| 442 | SYS_ARCH_DECL_PROTECT(lev);
|
---|
| 443 |
|
---|
| 444 | LWIP_UNUSED_ARG(name);
|
---|
| 445 | LWIP_UNUSED_ARG(stacksize);
|
---|
| 446 | LWIP_UNUSED_ARG(prio);
|
---|
| 447 |
|
---|
| 448 | new_thread = (struct threadlist*)malloc(sizeof(struct threadlist));
|
---|
| 449 | LWIP_ASSERT("new_thread != NULL", new_thread != NULL);
|
---|
| 450 | if (new_thread != NULL) {
|
---|
| 451 | new_thread->function = function;
|
---|
| 452 | new_thread->arg = arg;
|
---|
| 453 | SYS_ARCH_PROTECT(lev);
|
---|
| 454 | new_thread->next = lwip_win32_threads;
|
---|
| 455 | lwip_win32_threads = new_thread;
|
---|
| 456 |
|
---|
| 457 | h = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)sys_thread_function, new_thread, 0, &(new_thread->id));
|
---|
| 458 | LWIP_ASSERT("h != 0", h != 0);
|
---|
| 459 | LWIP_ASSERT("h != -1", h != INVALID_HANDLE_VALUE);
|
---|
| 460 | LWIP_UNUSED_ARG(h);
|
---|
| 461 | SetThreadName(new_thread->id, name);
|
---|
| 462 |
|
---|
| 463 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 464 | return new_thread->id;
|
---|
| 465 | }
|
---|
| 466 | return 0;
|
---|
| 467 | }
|
---|
| 468 |
|
---|
| 469 | #if !NO_SYS
|
---|
| 470 | #if LWIP_TCPIP_CORE_LOCKING
|
---|
| 471 |
|
---|
| 472 | static DWORD lwip_core_lock_holder_thread_id;
|
---|
| 473 |
|
---|
| 474 | void
|
---|
| 475 | sys_lock_tcpip_core(void)
|
---|
| 476 | {
|
---|
| 477 | sys_mutex_lock(&lock_tcpip_core);
|
---|
| 478 | lwip_core_lock_holder_thread_id = GetCurrentThreadId();
|
---|
| 479 | }
|
---|
| 480 |
|
---|
| 481 | void
|
---|
| 482 | sys_unlock_tcpip_core(void)
|
---|
| 483 | {
|
---|
| 484 | lwip_core_lock_holder_thread_id = 0;
|
---|
| 485 | sys_mutex_unlock(&lock_tcpip_core);
|
---|
| 486 | }
|
---|
| 487 | #endif /* LWIP_TCPIP_CORE_LOCKING */
|
---|
| 488 |
|
---|
| 489 | static DWORD lwip_tcpip_thread_id;
|
---|
| 490 |
|
---|
| 491 | void
|
---|
| 492 | sys_mark_tcpip_thread(void)
|
---|
| 493 | {
|
---|
| 494 | lwip_tcpip_thread_id = GetCurrentThreadId();
|
---|
| 495 | }
|
---|
| 496 |
|
---|
| 497 | void
|
---|
| 498 | sys_check_core_locking(void)
|
---|
| 499 | {
|
---|
| 500 | /* Embedded systems should check we are NOT in an interrupt context here */
|
---|
| 501 |
|
---|
| 502 | if (lwip_tcpip_thread_id != 0) {
|
---|
| 503 | DWORD current_thread_id = GetCurrentThreadId();
|
---|
| 504 |
|
---|
| 505 | #if LWIP_TCPIP_CORE_LOCKING
|
---|
| 506 | LWIP_ASSERT("Function called without core lock", current_thread_id == lwip_core_lock_holder_thread_id);
|
---|
| 507 | #else /* LWIP_TCPIP_CORE_LOCKING */
|
---|
| 508 | LWIP_ASSERT("Function called from wrong thread", current_thread_id == lwip_tcpip_thread_id);
|
---|
| 509 | #endif /* LWIP_TCPIP_CORE_LOCKING */
|
---|
| 510 | LWIP_UNUSED_ARG(current_thread_id); /* for LWIP_NOASSERT */
|
---|
| 511 | }
|
---|
| 512 | }
|
---|
| 513 | #endif /* !NO_SYS */
|
---|
| 514 |
|
---|
| 515 | err_t
|
---|
| 516 | sys_mbox_new(sys_mbox_t *mbox, int size)
|
---|
| 517 | {
|
---|
| 518 | LWIP_ASSERT("mbox != NULL", mbox != NULL);
|
---|
| 519 | LWIP_UNUSED_ARG(size);
|
---|
| 520 |
|
---|
| 521 | mbox->sem = CreateSemaphore(0, 0, MAX_QUEUE_ENTRIES, 0);
|
---|
| 522 | LWIP_ASSERT("Error creating semaphore", mbox->sem != NULL);
|
---|
| 523 | if (mbox->sem == NULL) {
|
---|
| 524 | SYS_ARCH_LOCKED(SYS_STATS_INC(mbox.err));
|
---|
| 525 | return ERR_MEM;
|
---|
| 526 | }
|
---|
| 527 | memset(&mbox->q_mem, 0, sizeof(u32_t)*MAX_QUEUE_ENTRIES);
|
---|
| 528 | mbox->head = 0;
|
---|
| 529 | mbox->tail = 0;
|
---|
| 530 | SYS_ARCH_LOCKED(SYS_STATS_INC_USED(mbox));
|
---|
| 531 | #if LWIP_STATS && SYS_STATS
|
---|
| 532 | LWIP_ASSERT("sys_mbox_new() counter overflow", lwip_stats.sys.mbox.used != 0);
|
---|
| 533 | #endif /* LWIP_STATS && SYS_STATS */
|
---|
| 534 | return ERR_OK;
|
---|
| 535 | }
|
---|
| 536 |
|
---|
| 537 | void
|
---|
| 538 | sys_mbox_free(sys_mbox_t *mbox)
|
---|
| 539 | {
|
---|
| 540 | /* parameter check */
|
---|
| 541 | LWIP_ASSERT("mbox != NULL", mbox != NULL);
|
---|
| 542 | LWIP_ASSERT("mbox->sem != NULL", mbox->sem != NULL);
|
---|
| 543 | LWIP_ASSERT("mbox->sem != INVALID_HANDLE_VALUE", mbox->sem != INVALID_HANDLE_VALUE);
|
---|
| 544 |
|
---|
| 545 | CloseHandle(mbox->sem);
|
---|
| 546 |
|
---|
| 547 | SYS_STATS_DEC(mbox.used);
|
---|
| 548 | #if LWIP_STATS && SYS_STATS
|
---|
| 549 | LWIP_ASSERT( "sys_mbox_free() ", lwip_stats.sys.mbox.used != (u16_t)-1);
|
---|
| 550 | #endif /* LWIP_STATS && SYS_STATS */
|
---|
| 551 | mbox->sem = NULL;
|
---|
| 552 | }
|
---|
| 553 |
|
---|
| 554 | void
|
---|
| 555 | sys_mbox_post(sys_mbox_t *q, void *msg)
|
---|
| 556 | {
|
---|
| 557 | BOOL ret;
|
---|
| 558 | SYS_ARCH_DECL_PROTECT(lev);
|
---|
| 559 | sys_arch_check_not_protected();
|
---|
| 560 |
|
---|
| 561 | /* parameter check */
|
---|
| 562 | LWIP_ASSERT("q != SYS_MBOX_NULL", q != SYS_MBOX_NULL);
|
---|
| 563 | LWIP_ASSERT("q->sem != NULL", q->sem != NULL);
|
---|
| 564 | LWIP_ASSERT("q->sem != INVALID_HANDLE_VALUE", q->sem != INVALID_HANDLE_VALUE);
|
---|
| 565 |
|
---|
| 566 | SYS_ARCH_PROTECT(lev);
|
---|
| 567 | q->q_mem[q->head] = msg;
|
---|
| 568 | q->head++;
|
---|
| 569 | if (q->head >= MAX_QUEUE_ENTRIES) {
|
---|
| 570 | q->head = 0;
|
---|
| 571 | }
|
---|
| 572 | LWIP_ASSERT("mbox is full!", q->head != q->tail);
|
---|
| 573 | ret = ReleaseSemaphore(q->sem, 1, 0);
|
---|
| 574 | LWIP_ASSERT("Error releasing sem", ret != 0);
|
---|
| 575 | LWIP_UNUSED_ARG(ret);
|
---|
| 576 |
|
---|
| 577 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 578 | }
|
---|
| 579 |
|
---|
| 580 | err_t
|
---|
| 581 | sys_mbox_trypost(sys_mbox_t *q, void *msg)
|
---|
| 582 | {
|
---|
| 583 | u32_t new_head;
|
---|
| 584 | BOOL ret;
|
---|
| 585 | SYS_ARCH_DECL_PROTECT(lev);
|
---|
| 586 | sys_arch_check_not_protected();
|
---|
| 587 |
|
---|
| 588 | /* parameter check */
|
---|
| 589 | LWIP_ASSERT("q != SYS_MBOX_NULL", q != SYS_MBOX_NULL);
|
---|
| 590 | LWIP_ASSERT("q->sem != NULL", q->sem != NULL);
|
---|
| 591 | LWIP_ASSERT("q->sem != INVALID_HANDLE_VALUE", q->sem != INVALID_HANDLE_VALUE);
|
---|
| 592 |
|
---|
| 593 | SYS_ARCH_PROTECT(lev);
|
---|
| 594 |
|
---|
| 595 | new_head = q->head + 1;
|
---|
| 596 | if (new_head >= MAX_QUEUE_ENTRIES) {
|
---|
| 597 | new_head = 0;
|
---|
| 598 | }
|
---|
| 599 | if (new_head == q->tail) {
|
---|
| 600 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 601 | return ERR_MEM;
|
---|
| 602 | }
|
---|
| 603 |
|
---|
| 604 | q->q_mem[q->head] = msg;
|
---|
| 605 | q->head = new_head;
|
---|
| 606 | LWIP_ASSERT("mbox is full!", q->head != q->tail);
|
---|
| 607 | ret = ReleaseSemaphore(q->sem, 1, 0);
|
---|
| 608 | LWIP_ASSERT("Error releasing sem", ret != 0);
|
---|
| 609 | LWIP_UNUSED_ARG(ret);
|
---|
| 610 |
|
---|
| 611 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 612 | return ERR_OK;
|
---|
| 613 | }
|
---|
| 614 |
|
---|
| 615 | err_t
|
---|
| 616 | sys_mbox_trypost_fromisr(sys_mbox_t *q, void *msg)
|
---|
| 617 | {
|
---|
| 618 | return sys_mbox_trypost(q, msg);
|
---|
| 619 | }
|
---|
| 620 |
|
---|
| 621 | u32_t
|
---|
| 622 | sys_arch_mbox_fetch(sys_mbox_t *q, void **msg, u32_t timeout)
|
---|
| 623 | {
|
---|
| 624 | DWORD ret;
|
---|
| 625 | LONGLONG starttime, endtime;
|
---|
| 626 | SYS_ARCH_DECL_PROTECT(lev);
|
---|
| 627 |
|
---|
| 628 | /* parameter check */
|
---|
| 629 | LWIP_ASSERT("q != SYS_MBOX_NULL", q != SYS_MBOX_NULL);
|
---|
| 630 | LWIP_ASSERT("q->sem != NULL", q->sem != NULL);
|
---|
| 631 | LWIP_ASSERT("q->sem != INVALID_HANDLE_VALUE", q->sem != INVALID_HANDLE_VALUE);
|
---|
| 632 |
|
---|
| 633 | if (timeout == 0) {
|
---|
| 634 | timeout = INFINITE;
|
---|
| 635 | }
|
---|
| 636 | starttime = sys_get_ms_longlong();
|
---|
| 637 | ret = WaitForSingleObject(q->sem, timeout);
|
---|
| 638 | if (ret == WAIT_OBJECT_0) {
|
---|
| 639 | SYS_ARCH_PROTECT(lev);
|
---|
| 640 | if (msg != NULL) {
|
---|
| 641 | *msg = q->q_mem[q->tail];
|
---|
| 642 | }
|
---|
| 643 |
|
---|
| 644 | q->tail++;
|
---|
| 645 | if (q->tail >= MAX_QUEUE_ENTRIES) {
|
---|
| 646 | q->tail = 0;
|
---|
| 647 | }
|
---|
| 648 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 649 | endtime = sys_get_ms_longlong();
|
---|
| 650 | return (u32_t)(endtime - starttime);
|
---|
| 651 | } else {
|
---|
| 652 | LWIP_ASSERT("Error waiting for sem", ret == WAIT_TIMEOUT);
|
---|
| 653 | if (msg != NULL) {
|
---|
| 654 | *msg = NULL;
|
---|
| 655 | }
|
---|
| 656 |
|
---|
| 657 | return SYS_ARCH_TIMEOUT;
|
---|
| 658 | }
|
---|
| 659 | }
|
---|
| 660 |
|
---|
| 661 | u32_t
|
---|
| 662 | sys_arch_mbox_tryfetch(sys_mbox_t *q, void **msg)
|
---|
| 663 | {
|
---|
| 664 | DWORD ret;
|
---|
| 665 | SYS_ARCH_DECL_PROTECT(lev);
|
---|
| 666 |
|
---|
| 667 | /* parameter check */
|
---|
| 668 | LWIP_ASSERT("q != SYS_MBOX_NULL", q != SYS_MBOX_NULL);
|
---|
| 669 | LWIP_ASSERT("q->sem != NULL", q->sem != NULL);
|
---|
| 670 | LWIP_ASSERT("q->sem != INVALID_HANDLE_VALUE", q->sem != INVALID_HANDLE_VALUE);
|
---|
| 671 |
|
---|
| 672 | ret = WaitForSingleObject(q->sem, 0);
|
---|
| 673 | if (ret == WAIT_OBJECT_0) {
|
---|
| 674 | SYS_ARCH_PROTECT(lev);
|
---|
| 675 | if (msg != NULL) {
|
---|
| 676 | *msg = q->q_mem[q->tail];
|
---|
| 677 | }
|
---|
| 678 |
|
---|
| 679 | q->tail++;
|
---|
| 680 | if (q->tail >= MAX_QUEUE_ENTRIES) {
|
---|
| 681 | q->tail = 0;
|
---|
| 682 | }
|
---|
| 683 | SYS_ARCH_UNPROTECT(lev);
|
---|
| 684 | return 0;
|
---|
| 685 | } else {
|
---|
| 686 | LWIP_ASSERT("Error waiting for sem", ret == WAIT_TIMEOUT);
|
---|
| 687 | if (msg != NULL) {
|
---|
| 688 | *msg = NULL;
|
---|
| 689 | }
|
---|
| 690 |
|
---|
| 691 | return SYS_ARCH_TIMEOUT;
|
---|
| 692 | }
|
---|
| 693 | }
|
---|
| 694 |
|
---|
| 695 | #if LWIP_NETCONN_SEM_PER_THREAD
|
---|
| 696 | sys_sem_t*
|
---|
| 697 | sys_arch_netconn_sem_get(void)
|
---|
| 698 | {
|
---|
| 699 | LPVOID tls_data = TlsGetValue(netconn_sem_tls_index);
|
---|
| 700 | return (sys_sem_t*)tls_data;
|
---|
| 701 | }
|
---|
| 702 |
|
---|
| 703 | void
|
---|
| 704 | sys_arch_netconn_sem_alloc(void)
|
---|
| 705 | {
|
---|
| 706 | sys_sem_t *sem;
|
---|
| 707 | err_t err;
|
---|
| 708 | BOOL done;
|
---|
| 709 |
|
---|
| 710 | sem = (sys_sem_t*)malloc(sizeof(sys_sem_t));
|
---|
| 711 | LWIP_ASSERT("failed to allocate memory for TLS semaphore", sem != NULL);
|
---|
| 712 | err = sys_sem_new(sem, 0);
|
---|
| 713 | LWIP_ASSERT("failed to initialise TLS semaphore", err == ERR_OK);
|
---|
| 714 | done = TlsSetValue(netconn_sem_tls_index, sem);
|
---|
| 715 | LWIP_UNUSED_ARG(done);
|
---|
| 716 | LWIP_ASSERT("failed to initialise TLS semaphore storage", done == TRUE);
|
---|
| 717 | }
|
---|
| 718 |
|
---|
| 719 | void
|
---|
| 720 | sys_arch_netconn_sem_free(void)
|
---|
| 721 | {
|
---|
| 722 | LPVOID tls_data = TlsGetValue(netconn_sem_tls_index);
|
---|
| 723 | if (tls_data != NULL) {
|
---|
| 724 | BOOL done;
|
---|
| 725 | free(tls_data);
|
---|
| 726 | done = TlsSetValue(netconn_sem_tls_index, NULL);
|
---|
| 727 | LWIP_UNUSED_ARG(done);
|
---|
| 728 | LWIP_ASSERT("failed to de-init TLS semaphore storage", done == TRUE);
|
---|
| 729 | }
|
---|
| 730 | }
|
---|
| 731 | #endif /* LWIP_NETCONN_SEM_PER_THREAD */
|
---|
| 732 |
|
---|
| 733 | #endif /* !NO_SYS */
|
---|
| 734 |
|
---|
| 735 | /* get keyboard state to terminate the debug app on any kbhit event using win32 API */
|
---|
| 736 | int
|
---|
| 737 | lwip_win32_keypressed(void)
|
---|
| 738 | {
|
---|
| 739 | INPUT_RECORD rec;
|
---|
| 740 | DWORD num = 0;
|
---|
| 741 | HANDLE h = GetStdHandle(STD_INPUT_HANDLE);
|
---|
| 742 | BOOL ret = PeekConsoleInput(h, &rec, 1, &num);
|
---|
| 743 | if (ret && num) {
|
---|
| 744 | ReadConsoleInput(h, &rec, 1, &num);
|
---|
| 745 | if (rec.EventType == KEY_EVENT) {
|
---|
| 746 | if (rec.Event.KeyEvent.bKeyDown) {
|
---|
| 747 | /* not a special key? */
|
---|
| 748 | if (rec.Event.KeyEvent.uChar.AsciiChar != 0) {
|
---|
| 749 | return 1;
|
---|
| 750 | }
|
---|
| 751 | }
|
---|
| 752 | }
|
---|
| 753 | }
|
---|
| 754 | return 0;
|
---|
| 755 | }
|
---|
| 756 |
|
---|
| 757 | #include <stdarg.h>
|
---|
| 758 |
|
---|
| 759 | /* This is an example implementation for LWIP_PLATFORM_DIAG:
|
---|
| 760 | * format a string and pass it to your output function.
|
---|
| 761 | */
|
---|
| 762 | void
|
---|
| 763 | lwip_win32_platform_diag(const char *format, ...)
|
---|
| 764 | {
|
---|
| 765 | va_list ap;
|
---|
| 766 | /* get the varargs */
|
---|
| 767 | va_start(ap, format);
|
---|
| 768 | /* print via varargs; to use another output function, you could use
|
---|
| 769 | vsnprintf here */
|
---|
| 770 | vprintf(format, ap);
|
---|
| 771 | va_end(ap);
|
---|
| 772 | }
|
---|