Pyrogenesis  13997
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
waio.cpp
Go to the documentation of this file.
1 /* Copyright (c) 2011 Wildfire Games
2  *
3  * Permission is hereby granted, free of charge, to any person obtaining
4  * a copy of this software and associated documentation files (the
5  * "Software"), to deal in the Software without restriction, including
6  * without limitation the rights to use, copy, modify, merge, publish,
7  * distribute, sublicense, and/or sell copies of the Software, and to
8  * permit persons to whom the Software is furnished to do so, subject to
9  * the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included
12  * in all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
18  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
19  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
20  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 /*
24  * emulate POSIX asynchronous I/O on Windows.
25  */
26 
27 // NB: this module is significantly faster than Intel's aio library,
28 // which also returns ERROR_INVALID_PARAMETER from aio_error if the
29 // file is opened with FILE_FLAG_OVERLAPPED. (it looks like they are
30 // using threaded blocking IO)
31 
32 #include "precompiled.h"
34 
35 #include "lib/bits.h" // round_up
36 #include "lib/alignment.h" // IsAligned
37 #include "lib/module_init.h"
38 #include "lib/sysdep/cpu.h" // cpu_AtomicAdd
39 #include "lib/sysdep/filesystem.h" // O_DIRECT
40 #include "lib/sysdep/os/win/wutil.h" // wutil_SetPrivilege
43 #include "lib/sysdep/os/win/wposix/crt_posix.h" // _get_osfhandle
44 
46 
47 // (dynamic linking preserves compatibility with previous Windows versions)
48 static WUTIL_FUNC(pSetFileCompletionNotificationModes, BOOL, (HANDLE, UCHAR));
49 static WUTIL_FUNC(pSetFileIoOverlappedRange, BOOL, (HANDLE, PUCHAR, ULONG));
50 static WUTIL_FUNC(pSetFileValidData, BOOL, (HANDLE, LONGLONG));
51 
52 // (there must be one global IOCP because aio_suspend might be called for
53 // requests from different files)
54 static HANDLE hIOCP;
55 
56 
57 //-----------------------------------------------------------------------------
58 // OpenFile
59 
60 static DWORD DesiredAccess(int oflag)
61 {
62  switch(oflag & (O_RDONLY|O_WRONLY|O_RDWR))
63  {
64  case O_RDONLY:
65  // (WinXP x64 requires FILE_WRITE_ATTRIBUTES for SetFileCompletionNotificationModes)
66  return GENERIC_READ|FILE_WRITE_ATTRIBUTES;
67  case O_WRONLY:
68  return GENERIC_WRITE;
69  case O_RDWR:
70  return GENERIC_READ|GENERIC_WRITE;
71  default:
73  return 0;
74  }
75 }
76 
77 static DWORD ShareMode(int oflag)
78 {
79  switch(oflag & (O_RDONLY|O_WRONLY|O_RDWR))
80  {
81  case O_RDONLY:
82  return FILE_SHARE_READ;
83  case O_WRONLY:
84  return FILE_SHARE_WRITE;
85  case O_RDWR:
86  return FILE_SHARE_WRITE; // deny read access (c.f. waio_Preallocate)
87  default:
89  return 0;
90  }
91 }
92 
93 static DWORD CreationDisposition(int oflag)
94 {
95  if(oflag & O_CREAT)
96  return (oflag & O_EXCL)? CREATE_NEW : CREATE_ALWAYS;
97 
98  if(oflag & O_TRUNC)
99  return TRUNCATE_EXISTING;
100 
101  return OPEN_EXISTING;
102 }
103 
105 {
106  // - FILE_FLAG_SEQUENTIAL_SCAN is ignored when FILE_FLAG_NO_BUFFERING
107  // is set (c.f. "Windows via C/C++", p. 324)
108  // - FILE_FLAG_WRITE_THROUGH is ~5% slower (diskspd.cpp suggests it
109  // disables hardware caching; the overhead may also be due to the
110  // Windows cache manager)
111  const DWORD flags = FILE_FLAG_OVERLAPPED|FILE_FLAG_NO_BUFFERING;
112  const DWORD attributes = FILE_ATTRIBUTE_NORMAL;
113  return flags|attributes;
114 }
115 
116 static Status OpenFile(const OsPath& pathname, int oflag, HANDLE& hFile)
117 {
119 
120  const DWORD access = DesiredAccess(oflag);
121  const DWORD share = ShareMode(oflag);
122  const DWORD create = CreationDisposition(oflag);
123  const DWORD flags = FlagsAndAttributes();
124  hFile = CreateFileW(OsString(pathname).c_str(), access, share, 0, create, flags, 0);
125  if(hFile == INVALID_HANDLE_VALUE)
127 
128  return INFO::OK;
129 }
130 
131 
132 //-----------------------------------------------------------------------------
133 // OvlAllocator
134 
135 // allocator for OVERLAPPED (enables a special optimization, see Associate)
136 struct OvlAllocator // POD
137 {
138  // freelist entries for (padded) OVERLAPPED from our storage
139  struct Entry
140  {
141  SLIST_ENTRY entry;
142  OVERLAPPED ovl;
143  };
144 
146  {
147  // the allocation must be naturally aligned to ensure it doesn't
148  // overlap another page, which might prevent SetFileIoOverlappedRange
149  // from pinning the pages if one of them is PAGE_NOACCESS.
150  storage = _mm_malloc(storageSize, storageSize);
151  if(!storage)
153  memset(storage, 0, storageSize);
154 
155  InitializeSListHead(&freelist);
156 
157  // storageSize provides more than enough OVERLAPPED, so we
158  // pad them to the cache line size to maybe avoid a few RFOs.
159  const size_t size = Align<cacheLineSize>(sizeof(Entry));
160  for(uintptr_t offset = 0; offset+size <= storageSize; offset += size)
161  {
162  Entry* entry = (Entry*)(uintptr_t(storage) + offset);
163  ENSURE(IsAligned(entry, MEMORY_ALLOCATION_ALIGNMENT));
164  InterlockedPushEntrySList(&freelist, &entry->entry);
165  }
166 
167  extant = 0;
168 
169  return INFO::OK;
170  }
171 
172  void Shutdown()
173  {
174  if(extant != 0)
175  debug_printf(L"waio: OvlAllocator::Shutdown with extant=%d\n", extant);
176 
177  InterlockedFlushSList(&freelist);
178 
179  _mm_free(storage);
180  storage = 0;
181  }
182 
183  // irrevocably enable a special optimization for all I/Os requests
184  // concerning this file, ending when the file is closed. has no effect
185  // unless Vista+ and SeLockMemoryPrivilege are available.
186  void Associate(HANDLE hFile)
187  {
188  ENSURE(extant == 0);
189 
190  // pin the page in kernel address space, which means our thread
191  // won't have to be the one to service the I/O, thus avoiding an APC.
192  // ("thread agnostic I/O")
193  if(pSetFileIoOverlappedRange)
194  WARN_IF_FALSE(pSetFileIoOverlappedRange(hFile, (PUCHAR)storage, storageSize));
195  }
196 
197  // @return OVERLAPPED initialized for I/O starting at offset,
198  // or 0 if all available structures have already been allocated.
199  OVERLAPPED* Allocate(off_t offset)
200  {
201  Entry* entry = (Entry*)InterlockedPopEntrySList(&freelist);
202  if(!entry)
203  return 0;
204 
205  OVERLAPPED& ovl = entry->ovl;
206  ovl.Internal = 0;
207  ovl.InternalHigh = 0;
208  ovl.Offset = u64_lo(offset);
209  ovl.OffsetHigh = u64_hi(offset);
210  ovl.hEvent = 0; // (notification is via IOCP and/or polling)
211 
212  cpu_AtomicAdd(&extant, +1);
213 
214  return &ovl;
215  }
216 
217  void Deallocate(OVERLAPPED* ovl)
218  {
219  cpu_AtomicAdd(&extant, -1);
220 
221  const uintptr_t address = uintptr_t(ovl);
222  ENSURE(uintptr_t(storage) <= address && address < uintptr_t(storage)+storageSize);
223  InterlockedPushEntrySList(&freelist, (PSLIST_ENTRY)(address - offsetof(Entry, ovl)));
224  }
225 
226  // one 4 KiB page is enough for 64 OVERLAPPED per file (i.e. plenty).
227  static const size_t storageSize = pageSize;
228 
229  void* storage;
230 
231 #if MSC_VERSION
232 # pragma warning(push)
233 # pragma warning(disable:4324) // structure was padded due to __declspec(align())
234 #endif
235  __declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) SLIST_HEADER freelist;
236 #if MSC_VERSION
237 # pragma warning(pop)
238 #endif
239 
240  volatile intptr_t extant;
241 };
242 
243 
244 //-----------------------------------------------------------------------------
245 // FileControlBlock
246 
247 // information required to start asynchronous I/Os from a file
248 struct FileControlBlock // POD
249 {
251 
253 
255  {
256  hFile = INVALID_HANDLE_VALUE;
257  return ovl.Init();
258  }
259 
260  void Shutdown()
261  {
262  ENSURE(hFile == INVALID_HANDLE_VALUE);
263  ovl.Shutdown();
264  }
265 
266  Status Open(const OsPath& pathname, int oflag)
267  {
268  RETURN_STATUS_IF_ERR(OpenFile(pathname, oflag, hFile));
269 
271 
272  AttachToCompletionPort(hFile, hIOCP, (ULONG_PTR)this);
273 
274  // minor optimization: avoid posting to IOCP in rare cases
275  // where the I/O completes synchronously
276  if(pSetFileCompletionNotificationModes)
277  {
278  // (for reasons as yet unknown, this fails when the file is
279  // opened for read-only access)
280  (void)pSetFileCompletionNotificationModes(hFile, FILE_SKIP_COMPLETION_PORT_ON_SUCCESS);
281  }
282 
283  return INFO::OK;
284  }
285 
287  {
288  const BOOL ok = CloseHandle(hFile);
289  hFile = INVALID_HANDLE_VALUE;
290  if(!ok)
292  return INFO::OK;
293  }
294 };
295 
296 
297 //-----------------------------------------------------------------------------
298 // FileControlBlocks
299 
300 struct FileControlBlocks // POD
301 {
302  // (we never open more than a few files at a time.)
303  static const size_t maxFiles = 8;
304 
305  // (our descriptors exceed _NHANDLE_ (2048) to ensure they are not
306  // confused with lowio descriptors.)
307  static const int firstDescriptor = 4000;
308 
310  CACHE_ALIGNED(volatile intptr_t) inUse[maxFiles];
311 
312  void Init()
313  {
314  for(size_t i = 0; i < maxFiles; i++)
315  {
316  inUse[i] = 0;
317  fcbs[i].Init();
318  }
319  }
320 
321  void Shutdown()
322  {
323  for(size_t i = 0; i < maxFiles; i++)
324  {
325  ENSURE(inUse[i] == 0);
326  fcbs[i].Shutdown();
327  }
328  }
329 
331  {
332  for(size_t i = 0; i < maxFiles; i++)
333  {
334  if(cpu_CAS(&inUse[i], 0, 1))
335  return &fcbs[i];
336  }
337 
338  return 0;
339  }
340 
342  {
343  const size_t index = fcb - &fcbs[0];
344  inUse[index] = 0;
345  }
346 
347  int Descriptor(FileControlBlock* fcb) const
348  {
349  const size_t index = fcb - &fcbs[0];
350  return firstDescriptor + (int)index;
351  }
352 
354  {
355  const size_t index = size_t(descriptor - firstDescriptor);
356  if(index >= maxFiles)
357  return 0;
358  if(!inUse[index])
359  return 0;
360  return &fcbs[index];
361  }
362 };
363 
365 
366 
367 //-----------------------------------------------------------------------------
368 // init/shutdown
369 
371 
372 // called from waio_Open (avoids overhead if this module is never used)
374 {
375  fileControlBlocks.Init();
376 
377  WUTIL_IMPORT_KERNEL32(SetFileCompletionNotificationModes, pSetFileCompletionNotificationModes);
378 
379  // NB: using these functions when the privileges are not available would
380  // trigger warnings. since callers have to check the function pointers
381  // anyway, just refrain from setting them in such cases.
382 
383  if(wutil_SetPrivilege(L"SeLockMemoryPrivilege", true) == INFO::OK)
384  WUTIL_IMPORT_KERNEL32(SetFileIoOverlappedRange, pSetFileIoOverlappedRange);
385 
386  if(wutil_SetPrivilege(L"SeManageVolumePrivilege", true) == INFO::OK)
387  WUTIL_IMPORT_KERNEL32(SetFileValidData, pSetFileValidData);
388 
389  return INFO::OK;
390 }
391 
392 
394 {
395  if(waio_initState == 0) // we were never initialized
396  return INFO::OK;
397 
398  fileControlBlocks.Shutdown();
399 
400  WARN_IF_FALSE(CloseHandle(hIOCP));
401 
402  return INFO::OK;
403 }
404 
405 
406 //-----------------------------------------------------------------------------
407 // Windows-only APIs
408 
409 Status waio_open(const OsPath& pathname, int oflag, ...)
410 {
411  ASSERT(oflag & O_DIRECT);
412  ENSURE(!(oflag & O_APPEND)); // not supported
413 
414  RETURN_STATUS_IF_ERR(ModuleInit(&waio_initState, waio_Init));
415 
416  FileControlBlock* fcb = fileControlBlocks.Allocate();
417  if(!fcb)
419 
420  RETURN_STATUS_IF_ERR(fcb->Open(pathname, oflag));
421  return (Status)fileControlBlocks.Descriptor(fcb);
422 }
423 
424 
426 {
427  FileControlBlock* fcb = fileControlBlocks.FromDescriptor(fd);
428  if(!fcb)
429  return ERR::INVALID_HANDLE; // NOWARN - fd might be from lowio
430 
431  Status ret = fcb->Close();
432  fileControlBlocks.Deallocate(fcb);
433  return ret;
434 }
435 
436 
438 {
440 
441  HANDLE hFile; // from FileControlBlock OR lowio
442  {
443  FileControlBlock* fcb = fileControlBlocks.FromDescriptor(fd);
444  if(fcb)
445  hFile = fcb->hFile;
446  else
447  {
448  hFile = (HANDLE)_get_osfhandle(fd);
449  if(hFile == INVALID_HANDLE_VALUE)
451  }
452  }
453 
454  // Windows requires sector alignment (see discussion in header)
455  const off_t alignedSize = round_up(size, (off_t)maxSectorSize); // (Align<> cannot compute off_t)
456 
457  // allocate all space up front to reduce fragmentation
458  LARGE_INTEGER size64; size64.QuadPart = alignedSize;
459  WARN_IF_FALSE(SetFilePointerEx(hFile, size64, 0, FILE_BEGIN));
460  if(!SetEndOfFile(hFile))
461  {
462  if(GetLastError() == ERROR_DISK_FULL)
463  SetLastError(0);
464  else
465  debug_printf(L"waio_Preallocate(%lld) failed: %d\n", size, GetLastError());
466  return ERR::FAIL; // NOWARN (either out of disk space, or error was printed)
467  }
468 
469  // avoid synchronous zero-fill (see discussion in header)
470  if(pSetFileValidData)
471  {
472  // this has been reported (#849) to fail with GetLastError() == 0 for
473  // both tiny and medium alignedSize, despite Administrator privileges.
474  // it seems the problem is the underlying FAT filesystem. Nick Ryan:
475  // "FastFat does not process the FILE_VALID_DATA_LENGTH_INFORMATION IOCTL"
476  // (http://us.generation-nt.com/answer/setfilevaliddata-help-25926952.html?page=2)
477  // verifying the filesystem is indeed FAT would be overkill; we'll just
478  // ignore the return code. however, GetLastError can be used to check
479  // whether other problems arose.
480  (void)pSetFileValidData(hFile, alignedSize);
481  ENSURE(GetLastError() == 0);
482  }
483 
484  return INFO::OK;
485 }
486 
487 
488 //-----------------------------------------------------------------------------
489 // helper functions
490 
491 // called by aio_read, aio_write, and lio_listio.
492 // cb->aio_lio_opcode specifies desired operation.
493 // @return -1 on failure (having also set errno)
494 static int Issue(aiocb* cb)
495 {
499 
500  FileControlBlock* fcb = fileControlBlocks.FromDescriptor(cb->aio_fildes);
501  if(!fcb)
502  {
504  errno = EINVAL;
505  return -1;
506  }
507 
508  ENSURE(!cb->ovl); // SUSv3: aiocb must not be in use
509  cb->ovl = fcb->ovl.Allocate(cb->aio_offset);
510  if(!cb->ovl)
511  {
513  errno = EMFILE;
514  return -1;
515  }
516 
518 
519  const HANDLE hFile = fcb->hFile;
520  void* const buf = (void*)cb->aio_buf; // from volatile void*
521  const DWORD size = u64_lo(cb->aio_nbytes);
522  ENSURE(u64_hi(cb->aio_nbytes) == 0);
523  OVERLAPPED* ovl = (OVERLAPPED*)cb->ovl;
524  // (there is no point in using WriteFileGather/ReadFileScatter here
525  // because the IO manager still needs to lock pages and translate them
526  // into an MDL, and we'd just be increasing the number of addresses)
527  const BOOL ok = (cb->aio_lio_opcode == LIO_WRITE)? WriteFile(hFile, buf, size, 0, ovl) : ReadFile(hFile, buf, size, 0, ovl);
528  if(ok || GetLastError() == ERROR_IO_PENDING)
529  return 0; // success
530 
531  const Status status = StatusFromWin();
532  WARN_IF_ERR(status);
533  errno = ErrnoFromStatus(status);
534  return -1;
535 }
536 
537 
538 static bool AreAnyComplete(const struct aiocb* const cbs[], int n)
539 {
540  for(int i = 0; i < n; i++)
541  {
542  if(!cbs[i]) // SUSv3: must ignore NULL entries
543  continue;
544 
545  if(HasOverlappedIoCompleted((OVERLAPPED*)cbs[i]->ovl))
546  return true;
547  }
548 
549  return false;
550 }
551 
552 
553 //-----------------------------------------------------------------------------
554 // API
555 
556 int aio_read(struct aiocb* cb)
557 {
558  cb->aio_lio_opcode = LIO_READ;
559  return Issue(cb);
560 }
561 
562 
563 int aio_write(struct aiocb* cb)
564 {
566  return Issue(cb);
567 }
568 
569 
570 int lio_listio(int mode, struct aiocb* const cbs[], int n, struct sigevent* se)
571 {
572  ENSURE(mode == LIO_WAIT || mode == LIO_NOWAIT);
573  UNUSED2(se); // signaling is not implemented.
574 
575  for(int i = 0; i < n; i++)
576  {
577  if(cbs[i] == 0 || cbs[i]->aio_lio_opcode == LIO_NOP)
578  continue;
579 
580  if(Issue(cbs[i]) == -1)
581  return -1;
582  }
583 
584  if(mode == LIO_WAIT)
585  return aio_suspend(cbs, n, 0);
586 
587  return 0;
588 }
589 
590 
591 int aio_suspend(const struct aiocb* const cbs[], int n, const struct timespec* timeout)
592 {
593  // consume all pending notifications to prevent them from piling up if
594  // requests are always complete by the time we're called
595  DWORD bytesTransferred; ULONG_PTR key; OVERLAPPED* ovl;
596  while(PollCompletionPort(hIOCP, 0, bytesTransferred, key, ovl) == INFO::OK) {}
597 
598  // avoid blocking if already complete (synchronous requests don't post notifications)
599  if(AreAnyComplete(cbs, n))
600  return 0;
601 
602  // caller doesn't want to block, and no requests are complete
603  if(timeout && timeout->tv_sec == 0 && timeout->tv_nsec == 0)
604  {
605  errno = EAGAIN;
606  return -1;
607  }
608 
609  // reduce CPU usage by blocking until a notification arrives or a
610  // brief timeout elapses (necessary because other threads - or even
611  // the above poll - might have consumed our notification). note that
612  // re-posting notifications that don't concern the respective requests
613  // is not desirable because POSIX doesn't require aio_suspend to be
614  // called, which means notifications might pile up.
615  const DWORD milliseconds = 1; // as short as possible (don't oversleep)
616  const Status ret = PollCompletionPort(hIOCP, milliseconds, bytesTransferred, key, ovl);
617  if(ret != INFO::OK && ret != ERR::AGAIN) // failed
618  {
620  return -1;
621  }
622 
623  // scan again (even if we got a notification, it might not concern THESE requests)
624  if(AreAnyComplete(cbs, n))
625  return 0;
626 
627  // none completed, must repeat the above steps. provoke being called again by
628  // claiming to have been interrupted by a signal.
629  errno = EINTR;
630  return -1;
631 }
632 
633 
634 int aio_error(const struct aiocb* cb)
635 {
636  const OVERLAPPED* ovl = (const OVERLAPPED*)cb->ovl;
637  if(!ovl) // called after aio_return
638  return EINVAL;
639  if(!HasOverlappedIoCompleted(ovl))
640  return EINPROGRESS;
641  if(ovl->Internal != ERROR_SUCCESS)
642  return EIO;
643  return 0;
644 }
645 
646 
648 {
649  FileControlBlock* fcb = fileControlBlocks.FromDescriptor(cb->aio_fildes);
650  OVERLAPPED* ovl = (OVERLAPPED*)cb->ovl;
651  if(!fcb || !ovl)
652  {
653  errno = EINVAL;
654  return -1;
655  }
656 
657  const ULONG_PTR status = ovl->Internal;
658  const ULONG_PTR bytesTransferred = ovl->InternalHigh;
659 
660  cb->ovl = 0; // prevent further calls to aio_error/aio_return
662  fcb->ovl.Deallocate(ovl);
663 
664  return (status == ERROR_SUCCESS)? bytesTransferred : -1;
665 }
666 
667 
668 // Win32 limitation: cancel all I/Os this thread issued for the given file
669 // (CancelIoEx can cancel individual operations, but is only
670 // available starting with Vista)
671 int aio_cancel(int fd, struct aiocb* UNUSED(cb))
672 {
673  FileControlBlock* fcb = fileControlBlocks.FromDescriptor(fd);
674  if(!fcb)
675  {
677  errno = EINVAL;
678  return -1;
679  }
680 
681  WARN_IF_FALSE(CancelIo(fcb->hFile));
682 
683  return AIO_CANCELED;
684 }
685 
686 
687 int aio_fsync(int, struct aiocb*)
688 {
690  errno = ENOSYS;
691  return -1;
692 }
Definition: waio.h:93
void Shutdown()
Definition: waio.cpp:260
static Status OpenFile(const OsPath &pathname, int oflag, HANDLE &hFile)
Definition: waio.cpp:116
const Status LOGIC
Definition: status.h:409
#define O_DIRECT
Definition: filesystem.h:67
static bool AreAnyComplete(const struct aiocb *const cbs[], int n)
Definition: waio.cpp:538
int aio_error(const struct aiocb *cb)
Definition: waio.cpp:634
int aio_suspend(const struct aiocb *const cbs[], int n, const struct timespec *timeout)
Definition: waio.cpp:591
static const size_t pageSize
Definition: alignment.h:61
#define UNUSED(param)
mark a function parameter as unused and avoid the corresponding compiler warning. ...
#define WARN_IF_ERR(expression)
Definition: status.h:265
size_t aio_nbytes
Definition: waio.h:68
#define COMPILER_FENCE
prevent the compiler from reordering loads or stores across this point.
Status waio_Preallocate(int fd, off_t size)
Definition: waio.cpp:437
__declspec(align(MEMORY_ALLOCATION_ALIGNMENT)) SLIST_HEADER freelist
const Status OK
Definition: status.h:386
some WinAPI functions SetLastError(0) on success, which is bad because it can hide previous errors...
Definition: wutil.h:119
FileControlBlock * Allocate()
Definition: waio.cpp:330
int aio_write(struct aiocb *cb)
Definition: waio.cpp:563
void Deallocate(OVERLAPPED *ovl)
Definition: waio.cpp:217
#define WUTIL_FUNC(varName, ret, params)
Definition: wutil.h:44
static const uintptr_t maxSectorSize
Definition: alignment.h:82
static ModuleInitState waio_initState
Definition: waio.cpp:370
T round_up(T n, T multiple)
round number up/down to the next given multiple.
Definition: bits.h:265
#define ASSERT(expr)
same as ENSURE in debug mode, does nothing in release mode.
Definition: debug.h:310
intptr_t cpu_AtomicAdd(volatile intptr_t *location, intptr_t increment)
add a signed value to a variable without the possibility of interference from other threads/CPUs...
Definition: arm.cpp:31
u32 u64_lo(u64 x)
return upper 32-bits
Definition: lib.cpp:49
int aio_fsync(int, struct aiocb *)
Definition: waio.cpp:687
#define WINIT_REGISTER_MAIN_SHUTDOWN(func)
Definition: winit.h:156
const Status INVALID_HANDLE
Definition: status.h:419
HANDLE hFile
Definition: waio.cpp:250
void Shutdown()
Definition: waio.cpp:321
void AttachToCompletionPort(HANDLE hFile, HANDLE &hIOCP, ULONG_PTR key, DWORD numConcurrentThreads)
Definition: wiocp.cpp:8
int BOOL
Definition: wgl.h:51
CACHE_ALIGNED(volatile intptr_t) inUse[maxFiles]
time_t tv_sec
Definition: wtime.h:64
SLIST_ENTRY entry
Definition: waio.cpp:141
volatile void * aio_buf
Definition: waio.h:67
const Status AGAIN
Definition: status.h:427
bool IsAligned(T t, uintptr_t multiple)
Definition: alignment.h:8
void Deallocate(FileControlBlock *fcb)
Definition: waio.cpp:341
const Status NOT_SUPPORTED
Definition: status.h:429
void Associate(HANDLE hFile)
Definition: waio.cpp:186
volatile intptr_t extant
Definition: waio.cpp:240
int ErrnoFromStatus(Status status)
Definition: status.cpp:93
#define ENSURE(expr)
ensure the expression &lt;expr&gt; evaluates to non-zero.
Definition: debug.h:282
#define UNUSED2(param)
mark a function local variable or parameter as unused and avoid the corresponding compiler warning...
intptr_t ModuleInitState
initialization state of a module (class, source file, etc.) must be initialized to zero (e...
Definition: module_init.h:35
bool WriteFile(void *cbdata, std::wstring cfgNsString, Path path)
Definition: waio.h:50
void Shutdown()
Definition: waio.cpp:172
ssize_t aio_return(struct aiocb *cb)
Definition: waio.cpp:647
int aio_lio_opcode
Definition: waio.h:71
int aio_cancel(int fd, struct aiocb *cb)
Definition: waio.cpp:671
long tv_nsec
Definition: wtime.h:65
const Status LIMIT
Definition: status.h:428
__int64 off_t
Definition: wposix_types.h:91
OVERLAPPED ovl
Definition: waio.cpp:142
Definition: path.h:75
void * HANDLE
Definition: wgl.h:62
Status PollCompletionPort(HANDLE hIOCP, DWORD timeout, DWORD &bytesTransferred, ULONG_PTR &key, OVERLAPPED *&ovl)
Definition: wiocp.cpp:18
unsigned long DWORD
Definition: wgl.h:56
pthread_key_t key
Definition: wpthread.cpp:140
Status StatusFromWin()
Definition: wutil.cpp:125
const Status INVALID_PARAM
Definition: status.h:423
static DWORD FlagsAndAttributes()
Definition: waio.cpp:104
void * ovl
Definition: waio.h:76
#define EINPROGRESS
Definition: werrno.h:86
i64 Status
Error handling system.
Definition: status.h:171
OvlAllocator ovl
Definition: waio.cpp:252
Status Close()
Definition: waio.cpp:286
static DWORD CreationDisposition(int oflag)
Definition: waio.cpp:93
Definition: waio.h:92
FileControlBlock fcbs[maxFiles]
Definition: waio.cpp:309
intptr_t ssize_t
Definition: wposix_types.h:82
static const size_t storageSize
Definition: waio.cpp:227
Status wutil_SetPrivilege(const wchar_t *privilege, bool enable)
Definition: wutil.cpp:459
int Descriptor(FileControlBlock *fcb) const
Definition: waio.cpp:347
#define DEBUG_WARN_ERR(status)
display the error dialog with text corresponding to the given error code.
Definition: debug.h:331
OVERLAPPED * Allocate(off_t offset)
Definition: waio.cpp:199
static HANDLE hIOCP
Definition: waio.cpp:54
JSBool ReadFile(JSContext *cx, uintN argc, jsval *vp)
static const size_t maxFiles
Definition: waio.cpp:303
Status Init()
Definition: waio.cpp:145
Definition: waio.h:63
Status waio_open(const OsPath &pathname, int oflag,...)
Definition: waio.cpp:409
bool cpu_CAS(volatile intptr_t *location, intptr_t expected, intptr_t newValue)
atomic &quot;compare and swap&quot;.
Definition: arm.cpp:36
#define WARN_IF_FALSE(expression)
Definition: status.h:360
static DWORD ShareMode(int oflag)
Definition: waio.cpp:77
int lio_listio(int mode, struct aiocb *const cbs[], int n, struct sigevent *se)
Definition: waio.cpp:570
static FileControlBlocks fileControlBlocks
Definition: waio.cpp:364
u32 u64_hi(u64 x)
Definition: lib.cpp:44
#define WARN_RETURN(status)
Definition: status.h:255
off_t aio_offset
Definition: waio.h:66
const Status FAIL
Definition: status.h:406
Definition: wtime.h:62
static const int firstDescriptor
Definition: waio.cpp:307
const Status NO_MEM
Definition: status.h:430
Status Open(const OsPath &pathname, int oflag)
Definition: waio.cpp:266
static DWORD DesiredAccess(int oflag)
Definition: waio.cpp:60
static int Issue(aiocb *cb)
Definition: waio.cpp:494
Status ModuleInit(volatile ModuleInitState *initState, Status(*init)())
calls a user-defined init function if initState is zero.
Definition: module_init.cpp:40
Definition: waio.h:91
int aio_read(struct aiocb *cb)
Definition: waio.cpp:556
Definition: waio.h:87
#define WUTIL_IMPORT_KERNEL32(procName, varName)
Definition: wutil.h:63
int aio_fildes
Definition: waio.h:65
static Status waio_Shutdown()
Definition: waio.cpp:393
static Status waio_Init()
Definition: waio.cpp:373
Status waio_close(int fd)
Definition: waio.cpp:425
void debug_printf(const wchar_t *fmt,...)
write a formatted string to the debug channel, subject to filtering (see below).
Definition: debug.cpp:142
static std::string OsString(const OsPath &path)
Definition: os_path.h:42
#define RETURN_STATUS_IF_ERR(expression)
Definition: status.h:276
Status Init()
Definition: waio.cpp:254
void * storage
Definition: waio.cpp:229
FileControlBlock * FromDescriptor(int descriptor)
Definition: waio.cpp:353