// // Copyright 2020 Staysail Systems, Inc. // Copyright 2018 Capitar IT Group BV // // This software is supplied under the terms of the MIT License, a // copy of which should be located in the distribution where this // file was obtained (LICENSE.txt). A copy of the license may also be // found online at https://opensource.org/licenses/MIT. // #include "core/nng_impl.h" #ifdef NNG_PLATFORM_WINDOWS #include // Windows IO Completion Port support. We basically create a single // IO completion port, then start threads on it. Handles are added // to the port on an as needed basis. We use a single IO completion // port for pretty much everything. static int win_io_nthr = 0; static HANDLE win_io_h = NULL; static nni_thr *win_io_thrs; static void win_io_handler(void *arg) { NNI_ARG_UNUSED(arg); for (;;) { DWORD cnt; BOOL ok; nni_win_io *item; OVERLAPPED *olpd = NULL; ULONG_PTR key = 0; int rv; ok = GetQueuedCompletionStatus( win_io_h, &cnt, &key, &olpd, INFINITE); if (olpd == NULL) { // Completion port closed... NNI_ASSERT(ok == FALSE); break; } item = CONTAINING_RECORD(olpd, nni_win_io, olpd); rv = ok ? 0 : nni_win_error(GetLastError()); item->cb(item, rv, (size_t) cnt); } } int nni_win_io_register(HANDLE h) { if (CreateIoCompletionPort(h, win_io_h, 0, 0) == NULL) { return (nni_win_error(GetLastError())); } return (0); } int nni_win_io_init(nni_win_io *io, nni_win_io_cb cb, void *ptr) { ZeroMemory(&io->olpd, sizeof(io->olpd)); io->cb = cb; io->ptr = ptr; io->aio = NULL; io->olpd.hEvent = CreateEvent(NULL, FALSE, FALSE, NULL); if (io->olpd.hEvent == NULL) { return (nni_win_error(GetLastError())); } return (0); } void nni_win_io_fini(nni_win_io *io) { if (io->olpd.hEvent != NULL) { CloseHandle((HANDLE) io->olpd.hEvent); } } int nni_win_io_sysinit(void) { HANDLE h; int i; int rv; int nthr = nni_plat_ncpu() * 2; // Limits on the thread count. This is fairly arbitrary. if (nthr < 4) { nthr = 4; } if (nthr > 64) { nthr = 64; } if ((win_io_thrs = NNI_ALLOC_STRUCTS(win_io_thrs, nthr)) == NULL) { return (NNG_ENOMEM); } win_io_nthr = nthr; h = CreateIoCompletionPort(INVALID_HANDLE_VALUE, NULL, 0, nthr); if (h == NULL) { return (nni_win_error(GetLastError())); } win_io_h = h; for (i = 0; i < win_io_nthr; i++) { rv = nni_thr_init(&win_io_thrs[i], win_io_handler, NULL); if (rv != 0) { goto fail; } nni_thr_set_name(&win_io_thrs[i], "nng:iocp"); } for (i = 0; i < win_io_nthr; i++) { nni_thr_run(&win_io_thrs[i]); } return (0); fail: nni_win_io_sysfini(); return (rv); } void nni_win_io_sysfini(void) { int i; HANDLE h; if ((h = win_io_h) != NULL) { CloseHandle(h); win_io_h = NULL; } for (i = 0; i < win_io_nthr; i++) { nni_thr_fini(&win_io_thrs[i]); } NNI_FREE_STRUCTS(win_io_thrs, win_io_nthr); } #endif // NNG_PLATFORM_WINDOWS