windows: drop XP support
[fio.git] / os / windows / posix.c
CommitLineData
9277ec14
BC
1/* This file contains functions which implement those POSIX and Linux functions
2 * that MinGW and Microsoft don't provide. The implementations contain just enough
3 * functionality to support fio.
4 */
5
6#include <arpa/inet.h>
7#include <netinet/in.h>
8#include <windows.h>
9#include <stddef.h>
ad9c0fbc 10#include <string.h>
9277ec14
BC
11#include <stdlib.h>
12#include <unistd.h>
13#include <dirent.h>
14#include <pthread.h>
f16b7405 15#include <time.h>
9277ec14
BC
16#include <semaphore.h>
17#include <sys/shm.h>
18#include <sys/mman.h>
19#include <sys/uio.h>
20#include <sys/resource.h>
8393ca93 21#include <poll.h>
70a61165
BC
22#include <sys/wait.h>
23#include <setjmp.h>
9277ec14
BC
24
25#include "../os-windows.h"
671b0600 26#include "../../lib/hweight.h"
9277ec14 27
8b6a404c
VF
28extern unsigned long mtime_since_now(struct timespec *);
29extern void fio_gettime(struct timespec *, void *);
21c75387 30
10a6b3c6
BC
31int win_to_posix_error(DWORD winerr)
32{
e8ed50bc 33 switch (winerr) {
bae743b1
JA
34 case ERROR_SUCCESS:
35 return 0;
e8ed50bc
JA
36 case ERROR_FILE_NOT_FOUND:
37 return ENOENT;
38 case ERROR_PATH_NOT_FOUND:
39 return ENOENT;
40 case ERROR_ACCESS_DENIED:
41 return EACCES;
42 case ERROR_INVALID_HANDLE:
43 return EBADF;
44 case ERROR_NOT_ENOUGH_MEMORY:
45 return ENOMEM;
46 case ERROR_INVALID_DATA:
47 return EINVAL;
48 case ERROR_OUTOFMEMORY:
49 return ENOMEM;
50 case ERROR_INVALID_DRIVE:
51 return ENODEV;
52 case ERROR_NOT_SAME_DEVICE:
53 return EXDEV;
54 case ERROR_WRITE_PROTECT:
55 return EROFS;
56 case ERROR_BAD_UNIT:
57 return ENODEV;
58 case ERROR_NOT_READY:
59 return EAGAIN;
60 case ERROR_SHARING_VIOLATION:
61 return EACCES;
62 case ERROR_LOCK_VIOLATION:
63 return EACCES;
64 case ERROR_SHARING_BUFFER_EXCEEDED:
65 return ENOLCK;
66 case ERROR_HANDLE_DISK_FULL:
67 return ENOSPC;
68 case ERROR_NOT_SUPPORTED:
69 return ENOSYS;
70 case ERROR_FILE_EXISTS:
71 return EEXIST;
72 case ERROR_CANNOT_MAKE:
73 return EPERM;
74 case ERROR_INVALID_PARAMETER:
75 return EINVAL;
76 case ERROR_NO_PROC_SLOTS:
77 return EAGAIN;
78 case ERROR_BROKEN_PIPE:
79 return EPIPE;
80 case ERROR_OPEN_FAILED:
81 return EIO;
82 case ERROR_NO_MORE_SEARCH_HANDLES:
83 return ENFILE;
84 case ERROR_CALL_NOT_IMPLEMENTED:
85 return ENOSYS;
86 case ERROR_INVALID_NAME:
87 return ENOENT;
88 case ERROR_WAIT_NO_CHILDREN:
89 return ECHILD;
90 case ERROR_CHILD_NOT_COMPLETE:
91 return EBUSY;
92 case ERROR_DIR_NOT_EMPTY:
93 return ENOTEMPTY;
94 case ERROR_SIGNAL_REFUSED:
95 return EIO;
96 case ERROR_BAD_PATHNAME:
97 return ENOENT;
98 case ERROR_SIGNAL_PENDING:
99 return EBUSY;
100 case ERROR_MAX_THRDS_REACHED:
101 return EAGAIN;
102 case ERROR_BUSY:
103 return EBUSY;
104 case ERROR_ALREADY_EXISTS:
105 return EEXIST;
106 case ERROR_NO_SIGNAL_SENT:
107 return EIO;
108 case ERROR_FILENAME_EXCED_RANGE:
109 return EINVAL;
110 case ERROR_META_EXPANSION_TOO_LONG:
111 return EINVAL;
112 case ERROR_INVALID_SIGNAL_NUMBER:
113 return EINVAL;
114 case ERROR_THREAD_1_INACTIVE:
115 return EINVAL;
116 case ERROR_BAD_PIPE:
117 return EINVAL;
118 case ERROR_PIPE_BUSY:
119 return EBUSY;
120 case ERROR_NO_DATA:
121 return EPIPE;
122 case ERROR_MORE_DATA:
123 return EAGAIN;
124 case ERROR_DIRECTORY:
125 return ENOTDIR;
126 case ERROR_PIPE_CONNECTED:
127 return EBUSY;
128 case ERROR_NO_TOKEN:
129 return EINVAL;
130 case ERROR_PROCESS_ABORTED:
131 return EFAULT;
132 case ERROR_BAD_DEVICE:
133 return ENODEV;
134 case ERROR_BAD_USERNAME:
135 return EINVAL;
136 case ERROR_OPEN_FILES:
137 return EAGAIN;
138 case ERROR_ACTIVE_CONNECTIONS:
139 return EAGAIN;
140 case ERROR_DEVICE_IN_USE:
141 return EBUSY;
142 case ERROR_INVALID_AT_INTERRUPT_TIME:
143 return EINTR;
144 case ERROR_IO_DEVICE:
145 return EIO;
146 case ERROR_NOT_OWNER:
147 return EPERM;
148 case ERROR_END_OF_MEDIA:
149 return ENOSPC;
150 case ERROR_EOM_OVERFLOW:
151 return ENOSPC;
152 case ERROR_BEGINNING_OF_MEDIA:
153 return ESPIPE;
154 case ERROR_SETMARK_DETECTED:
155 return ESPIPE;
156 case ERROR_NO_DATA_DETECTED:
157 return ENOSPC;
158 case ERROR_POSSIBLE_DEADLOCK:
159 return EDEADLOCK;
160 case ERROR_CRC:
161 return EIO;
162 case ERROR_NEGATIVE_SEEK:
163 return EINVAL;
164 case ERROR_DISK_FULL:
165 return ENOSPC;
166 case ERROR_NOACCESS:
167 return EFAULT;
168 case ERROR_FILE_INVALID:
169 return ENXIO;
749dff99 170 default:
4937100f 171 log_err("fio: windows error %lu not handled\n", winerr);
749dff99 172 return EIO;
10a6b3c6
BC
173 }
174
175 return winerr;
176}
177
671b0600
BC
178int GetNumLogicalProcessors(void)
179{
180 SYSTEM_LOGICAL_PROCESSOR_INFORMATION *processor_info = NULL;
181 DWORD len = 0;
182 DWORD num_processors = 0;
183 DWORD error = 0;
184 DWORD i;
185
186 while (!GetLogicalProcessorInformation(processor_info, &len)) {
187 error = GetLastError();
188 if (error == ERROR_INSUFFICIENT_BUFFER)
189 processor_info = malloc(len);
190 else {
4937100f
SW
191 log_err("Error: GetLogicalProcessorInformation failed: %lu\n",
192 error);
671b0600
BC
193 return -1;
194 }
195
196 if (processor_info == NULL) {
197 log_err("Error: failed to allocate memory for GetLogicalProcessorInformation");
198 return -1;
199 }
200 }
201
e8ed50bc 202 for (i = 0; i < len / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); i++) {
671b0600 203 if (processor_info[i].Relationship == RelationProcessorCore)
4ee47af0 204 num_processors += hweight64(processor_info[i].ProcessorMask);
671b0600
BC
205 }
206
207 free(processor_info);
208 return num_processors;
209}
210
9277ec14
BC
211long sysconf(int name)
212{
671b0600 213 long val = -1;
01d26955 214 long val2 = -1;
9277ec14
BC
215 SYSTEM_INFO sysInfo;
216 MEMORYSTATUSEX status;
217
e8ed50bc 218 switch (name) {
9277ec14 219 case _SC_NPROCESSORS_ONLN:
671b0600
BC
220 val = GetNumLogicalProcessors();
221 if (val == -1)
01d26955 222 log_err("sysconf(_SC_NPROCESSORS_ONLN) failed\n");
671b0600 223
9277ec14
BC
224 break;
225
226 case _SC_PAGESIZE:
227 GetSystemInfo(&sysInfo);
228 val = sysInfo.dwPageSize;
229 break;
230
231 case _SC_PHYS_PAGES:
232 status.dwLength = sizeof(status);
01d26955
BC
233 val2 = sysconf(_SC_PAGESIZE);
234 if (GlobalMemoryStatusEx(&status) && val2 != -1)
235 val = status.ullTotalPhys / val2;
236 else
237 log_err("sysconf(_SC_PHYS_PAGES) failed\n");
9277ec14
BC
238 break;
239 default:
240 log_err("sysconf(%d) is not implemented\n", name);
241 break;
242 }
243
244 return val;
245}
246
247char *dl_error = NULL;
248
249int dlclose(void *handle)
250{
251 return !FreeLibrary((HMODULE)handle);
252}
253
254void *dlopen(const char *file, int mode)
255{
256 HMODULE hMod;
257
258 hMod = LoadLibrary(file);
259 if (hMod == INVALID_HANDLE_VALUE)
260 dl_error = (char*)"LoadLibrary failed";
261 else
262 dl_error = NULL;
263
264 return hMod;
265}
266
267void *dlsym(void *handle, const char *name)
268{
269 FARPROC fnPtr;
270
271 fnPtr = GetProcAddress((HMODULE)handle, name);
272 if (fnPtr == NULL)
273 dl_error = (char*)"GetProcAddress failed";
274 else
275 dl_error = NULL;
276
277 return fnPtr;
278}
279
280char *dlerror(void)
281{
282 return dl_error;
283}
284
ba55bfa9
BC
285/* Copied from http://blogs.msdn.com/b/joshpoley/archive/2007/12/19/date-time-formats-and-conversions.aspx */
286void Time_tToSystemTime(time_t dosTime, SYSTEMTIME *systemTime)
287{
e8ed50bc
JA
288 FILETIME utcFT;
289 LONGLONG jan1970;
7ff0297f 290 SYSTEMTIME tempSystemTime;
5de1ade5 291
e8ed50bc
JA
292 jan1970 = Int32x32To64(dosTime, 10000000) + 116444736000000000;
293 utcFT.dwLowDateTime = (DWORD)jan1970;
294 utcFT.dwHighDateTime = jan1970 >> 32;
ba55bfa9 295
e8ed50bc 296 FileTimeToSystemTime((FILETIME*)&utcFT, &tempSystemTime);
7ff0297f 297 SystemTimeToTzSpecificLocalTime(NULL, &tempSystemTime, systemTime);
ba55bfa9
BC
298}
299
e8ed50bc 300char *ctime_r(const time_t *t, char *buf)
ba55bfa9 301{
e8ed50bc
JA
302 SYSTEMTIME systime;
303 const char * const dayOfWeek[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
304 const char * const monthOfYear[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
305
306 Time_tToSystemTime(*t, &systime);
307
308 /*
309 * We don't know how long `buf` is, but assume it's rounded up from
310 * the minimum of 25 to 32
311 */
a4820445
BVA
312 snprintf(buf, 32, "%s %s %d %02d:%02d:%02d %04d\n",
313 dayOfWeek[systime.wDayOfWeek % 7],
314 monthOfYear[(systime.wMonth - 1) % 12],
315 systime.wDay, systime.wHour, systime.wMinute,
316 systime.wSecond, systime.wYear);
e8ed50bc 317 return buf;
ba55bfa9
BC
318}
319
9277ec14
BC
320int gettimeofday(struct timeval *restrict tp, void *restrict tzp)
321{
322 FILETIME fileTime;
9576f613
BC
323 uint64_t unix_time, windows_time;
324 const uint64_t MILLISECONDS_BETWEEN_1601_AND_1970 = 11644473600000;
9277ec14 325
fc0b830f 326 /* Ignore the timezone parameter */
9277ec14
BC
327 (void)tzp;
328
329 /*
330 * Windows time is stored as the number 100 ns intervals since January 1 1601.
331 * Conversion details from http://www.informit.com/articles/article.aspx?p=102236&seqNum=3
332 * Its precision is 100 ns but accuracy is only one clock tick, or normally around 15 ms.
333 */
334 GetSystemTimeAsFileTime(&fileTime);
9576f613 335 windows_time = ((uint64_t)fileTime.dwHighDateTime << 32) + fileTime.dwLowDateTime;
9277ec14
BC
336 /* Divide by 10,000 to convert to ms and subtract the time between 1601 and 1970 */
337 unix_time = (((windows_time)/10000) - MILLISECONDS_BETWEEN_1601_AND_1970);
338 /* unix_time is now the number of milliseconds since 1970 (the Unix epoch) */
339 tp->tv_sec = unix_time / 1000;
340 tp->tv_usec = (unix_time % 1000) * 1000;
341 return 0;
342}
343
e8ed50bc 344int sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
9277ec14 345{
e5b8f91c
BC
346 int rc = 0;
347 void (*prev_handler)(int);
348
349 prev_handler = signal(sig, act->sa_handler);
350 if (oact != NULL)
351 oact->sa_handler = prev_handler;
352
353 if (prev_handler == SIG_ERR)
354 rc = -1;
355
356 return rc;
9277ec14
BC
357}
358
e8ed50bc 359int lstat(const char *path, struct stat *buf)
9277ec14
BC
360{
361 return stat(path, buf);
362}
363
e8ed50bc 364void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off)
9277ec14
BC
365{
366 DWORD vaProt = 0;
06cbb3c7
RC
367 DWORD mapAccess = 0;
368 DWORD lenlow;
369 DWORD lenhigh;
370 HANDLE hMap;
9277ec14
BC
371 void* allocAddr = NULL;
372
373 if (prot & PROT_NONE)
374 vaProt |= PAGE_NOACCESS;
375
06cbb3c7 376 if ((prot & PROT_READ) && !(prot & PROT_WRITE)) {
9277ec14 377 vaProt |= PAGE_READONLY;
06cbb3c7
RC
378 mapAccess = FILE_MAP_READ;
379 }
9277ec14 380
06cbb3c7 381 if (prot & PROT_WRITE) {
9277ec14 382 vaProt |= PAGE_READWRITE;
06cbb3c7
RC
383 mapAccess |= FILE_MAP_WRITE;
384 }
385
386 lenlow = len & 0xFFFF;
387 lenhigh = len >> 16;
388 /* If the low DWORD is zero and the high DWORD is non-zero, `CreateFileMapping`
389 will return ERROR_INVALID_PARAMETER. To avoid this, set both to zero. */
e8ed50bc 390 if (lenlow == 0)
06cbb3c7 391 lenhigh = 0;
9277ec14 392
e8ed50bc 393 if (flags & MAP_ANON || flags & MAP_ANONYMOUS) {
9277ec14 394 allocAddr = VirtualAlloc(addr, len, MEM_COMMIT, vaProt);
10a6b3c6
BC
395 if (allocAddr == NULL)
396 errno = win_to_posix_error(GetLastError());
e8ed50bc
JA
397 } else {
398 hMap = CreateFileMapping((HANDLE)_get_osfhandle(fildes), NULL,
399 vaProt, lenhigh, lenlow, NULL);
06cbb3c7
RC
400
401 if (hMap != NULL)
e8ed50bc
JA
402 allocAddr = MapViewOfFile(hMap, mapAccess, off >> 16,
403 off & 0xFFFF, len);
06cbb3c7
RC
404 if (hMap == NULL || allocAddr == NULL)
405 errno = win_to_posix_error(GetLastError());
406
407 }
9277ec14
BC
408
409 return allocAddr;
410}
411
412int munmap(void *addr, size_t len)
413{
06cbb3c7
RC
414 BOOL success;
415
416 /* We may have allocated the memory with either MapViewOfFile or
417 VirtualAlloc. Therefore, try calling UnmapViewOfFile first, and if that
418 fails, call VirtualFree. */
419 success = UnmapViewOfFile(addr);
420
421 if (!success)
06cbb3c7 422 success = VirtualFree(addr, 0, MEM_RELEASE);
10a6b3c6 423
06cbb3c7
RC
424 return !success;
425}
426
427int msync(void *addr, size_t len, int flags)
428{
429 return !FlushViewOfFile(addr, len);
9277ec14
BC
430}
431
432int fork(void)
433{
434 log_err("%s is not implemented\n", __func__);
435 errno = ENOSYS;
10a6b3c6 436 return -1;
9277ec14
BC
437}
438
439pid_t setsid(void)
440{
441 log_err("%s is not implemented\n", __func__);
442 errno = ENOSYS;
10a6b3c6 443 return -1;
9277ec14
BC
444}
445
ad9c0fbc
BC
446static HANDLE log_file = INVALID_HANDLE_VALUE;
447
9277ec14
BC
448void openlog(const char *ident, int logopt, int facility)
449{
e8ed50bc
JA
450 if (log_file != INVALID_HANDLE_VALUE)
451 return;
452
453 log_file = CreateFileA("syslog.txt", GENERIC_WRITE,
454 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
455 OPEN_ALWAYS, 0, NULL);
9277ec14
BC
456}
457
458void closelog(void)
459{
ad9c0fbc
BC
460 CloseHandle(log_file);
461 log_file = INVALID_HANDLE_VALUE;
462}
463
464void syslog(int priority, const char *message, ... /* argument */)
465{
466 va_list v;
467 int len;
468 char *output;
469 DWORD bytes_written;
470
471 if (log_file == INVALID_HANDLE_VALUE) {
e8ed50bc
JA
472 log_file = CreateFileA("syslog.txt", GENERIC_WRITE,
473 FILE_SHARE_READ | FILE_SHARE_WRITE,
474 NULL, OPEN_ALWAYS, 0, NULL);
ad9c0fbc
BC
475 }
476
477 if (log_file == INVALID_HANDLE_VALUE) {
478 log_err("syslog: failed to open log file\n");
479 return;
480 }
481
482 va_start(v, message);
483 len = _vscprintf(message, v);
484 output = malloc(len + sizeof(char));
98dc2db5 485 vsprintf(output, message, v);
ad9c0fbc
BC
486 WriteFile(log_file, output, len, &bytes_written, NULL);
487 va_end(v);
98dc2db5 488 free(output);
9277ec14
BC
489}
490
491int kill(pid_t pid, int sig)
492{
493 errno = ESRCH;
10a6b3c6 494 return -1;
9277ec14
BC
495}
496
fc0b830f
BC
497/*
498 * This is assumed to be used only by the network code,
499 * and so doesn't try and handle any of the other cases
500 */
9277ec14
BC
501int fcntl(int fildes, int cmd, ...)
502{
fc0b830f
BC
503 /*
504 * non-blocking mode doesn't work the same as in BSD sockets,
505 * so ignore it.
506 */
9277ec14
BC
507#if 0
508 va_list ap;
509 int val, opt, status;
510
511 if (cmd == F_GETFL)
512 return 0;
513 else if (cmd != F_SETFL) {
514 errno = EINVAL;
10a6b3c6 515 return -1;
9277ec14
BC
516 }
517
518 va_start(ap, 1);
519
520 opt = va_arg(ap, int);
521 if (opt & O_NONBLOCK)
522 val = 1;
523 else
524 val = 0;
525
526 status = ioctlsocket((SOCKET)fildes, opt, &val);
527
528 if (status == SOCKET_ERROR) {
529 errno = EINVAL;
530 val = -1;
531 }
532
533 va_end(ap);
534
535 return val;
536#endif
537return 0;
538}
539
540/*
541 * Get the value of a local clock source.
542 * This implementation supports 2 clocks: CLOCK_MONOTONIC provides high-accuracy
543 * relative time, while CLOCK_REALTIME provides a low-accuracy wall time.
544 */
545int clock_gettime(clockid_t clock_id, struct timespec *tp)
546{
547 int rc = 0;
548
e8ed50bc 549 if (clock_id == CLOCK_MONOTONIC) {
9277ec14
BC
550 static LARGE_INTEGER freq = {{0,0}};
551 LARGE_INTEGER counts;
5aa23eb8 552 uint64_t t;
9277ec14
BC
553
554 QueryPerformanceCounter(&counts);
555 if (freq.QuadPart == 0)
556 QueryPerformanceFrequency(&freq);
557
558 tp->tv_sec = counts.QuadPart / freq.QuadPart;
559 /* Get the difference between the number of ns stored
560 * in 'tv_sec' and that stored in 'counts' */
5aa23eb8 561 t = tp->tv_sec * freq.QuadPart;
9277ec14
BC
562 t = counts.QuadPart - t;
563 /* 't' now contains the number of cycles since the last second.
564 * We want the number of nanoseconds, so multiply out by 1,000,000,000
565 * and then divide by the frequency. */
566 t *= 1000000000;
567 tp->tv_nsec = t / freq.QuadPart;
e8ed50bc 568 } else if (clock_id == CLOCK_REALTIME) {
9277ec14
BC
569 /* clock_gettime(CLOCK_REALTIME,...) is just an alias for gettimeofday with a
570 * higher-precision field. */
571 struct timeval tv;
572 gettimeofday(&tv, NULL);
573 tp->tv_sec = tv.tv_sec;
574 tp->tv_nsec = tv.tv_usec * 1000;
575 } else {
576 errno = EINVAL;
577 rc = -1;
578 }
579
580 return rc;
581}
582
583int mlock(const void * addr, size_t len)
584{
10a6b3c6
BC
585 SIZE_T min, max;
586 BOOL success;
587 HANDLE process = GetCurrentProcess();
588
589 success = GetProcessWorkingSetSize(process, &min, &max);
590 if (!success) {
591 errno = win_to_posix_error(GetLastError());
592 return -1;
593 }
594
595 min += len;
596 max += len;
597 success = SetProcessWorkingSetSize(process, min, max);
598 if (!success) {
599 errno = win_to_posix_error(GetLastError());
600 return -1;
601 }
602
603 success = VirtualLock((LPVOID)addr, len);
604 if (!success) {
605 errno = win_to_posix_error(GetLastError());
606 return -1;
607 }
608
609 return 0;
9277ec14
BC
610}
611
612int munlock(const void * addr, size_t len)
613{
10a6b3c6 614 BOOL success = VirtualUnlock((LPVOID)addr, len);
e8ed50bc 615
10a6b3c6
BC
616 if (!success) {
617 errno = win_to_posix_error(GetLastError());
618 return -1;
619 }
620
621 return 0;
9277ec14
BC
622}
623
624pid_t waitpid(pid_t pid, int *stat_loc, int options)
625{
626 log_err("%s is not implemented\n", __func__);
627 errno = ENOSYS;
628 return -1;
629}
630
631int usleep(useconds_t useconds)
632{
633 Sleep(useconds / 1000);
634 return 0;
635}
636
637char *basename(char *path)
638{
639 static char name[MAX_PATH];
640 int i;
641
642 if (path == NULL || strlen(path) == 0)
643 return (char*)".";
644
645 i = strlen(path) - 1;
646
9576f613 647 while (path[i] != '\\' && path[i] != '/' && i >= 0)
9277ec14
BC
648 i--;
649
13a85be9
TK
650 name[MAX_PATH - 1] = '\0';
651 strncpy(name, path + i + 1, MAX_PATH - 1);
9277ec14
BC
652
653 return name;
654}
655
9277ec14
BC
656int fsync(int fildes)
657{
658 HANDLE hFile = (HANDLE)_get_osfhandle(fildes);
10a6b3c6
BC
659 if (!FlushFileBuffers(hFile)) {
660 errno = win_to_posix_error(GetLastError());
661 return -1;
662 }
663
664 return 0;
9277ec14
BC
665}
666
667int nFileMappings = 0;
668HANDLE fileMappings[1024];
669
670int shmget(key_t key, size_t size, int shmflg)
671{
672 int mapid = -1;
d3987946
BC
673 uint32_t size_low = size & 0xFFFFFFFF;
674 uint32_t size_high = ((uint64_t)size) >> 32;
e8ed50bc
JA
675 HANDLE hMapping;
676
677 hMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
678 PAGE_EXECUTE_READWRITE | SEC_RESERVE,
679 size_high, size_low, NULL);
9277ec14
BC
680 if (hMapping != NULL) {
681 fileMappings[nFileMappings] = hMapping;
682 mapid = nFileMappings;
683 nFileMappings++;
e8ed50bc 684 } else
9277ec14 685 errno = ENOSYS;
9277ec14
BC
686
687 return mapid;
688}
689
690void *shmat(int shmid, const void *shmaddr, int shmflg)
691{
e8ed50bc 692 void *mapAddr;
9277ec14 693 MEMORY_BASIC_INFORMATION memInfo;
e8ed50bc 694
9277ec14 695 mapAddr = MapViewOfFile(fileMappings[shmid], FILE_MAP_ALL_ACCESS, 0, 0, 0);
10a6b3c6
BC
696 if (mapAddr == NULL) {
697 errno = win_to_posix_error(GetLastError());
698 return (void*)-1;
699 }
700
701 if (VirtualQuery(mapAddr, &memInfo, sizeof(memInfo)) == 0) {
702 errno = win_to_posix_error(GetLastError());
703 return (void*)-1;
704 }
705
9277ec14 706 mapAddr = VirtualAlloc(mapAddr, memInfo.RegionSize, MEM_COMMIT, PAGE_READWRITE);
10a6b3c6
BC
707 if (mapAddr == NULL) {
708 errno = win_to_posix_error(GetLastError());
709 return (void*)-1;
710 }
711
9277ec14
BC
712 return mapAddr;
713}
714
715int shmdt(const void *shmaddr)
716{
10a6b3c6
BC
717 if (!UnmapViewOfFile(shmaddr)) {
718 errno = win_to_posix_error(GetLastError());
719 return -1;
720 }
721
722 return 0;
9277ec14
BC
723}
724
725int shmctl(int shmid, int cmd, struct shmid_ds *buf)
726{
727 if (cmd == IPC_RMID) {
728 fileMappings[shmid] = INVALID_HANDLE_VALUE;
729 return 0;
9277ec14 730 }
e8ed50bc
JA
731
732 log_err("%s is not implemented\n", __func__);
10a6b3c6
BC
733 errno = ENOSYS;
734 return -1;
9277ec14
BC
735}
736
737int setuid(uid_t uid)
738{
739 log_err("%s is not implemented\n", __func__);
740 errno = ENOSYS;
10a6b3c6 741 return -1;
9277ec14
BC
742}
743
744int setgid(gid_t gid)
745{
746 log_err("%s is not implemented\n", __func__);
747 errno = ENOSYS;
10a6b3c6 748 return -1;
9277ec14
BC
749}
750
751int nice(int incr)
752{
24a2bb13 753 DWORD prioclass = NORMAL_PRIORITY_CLASS;
1e7fa601 754
24a2bb13
BC
755 if (incr < -15)
756 prioclass = HIGH_PRIORITY_CLASS;
757 else if (incr < 0)
758 prioclass = ABOVE_NORMAL_PRIORITY_CLASS;
759 else if (incr > 15)
760 prioclass = IDLE_PRIORITY_CLASS;
761 else if (incr > 0)
762 prioclass = BELOW_NORMAL_PRIORITY_CLASS;
1e7fa601 763
24a2bb13
BC
764 if (!SetPriorityClass(GetCurrentProcess(), prioclass))
765 log_err("fio: SetPriorityClass failed\n");
9277ec14
BC
766
767 return 0;
768}
769
770int getrusage(int who, struct rusage *r_usage)
771{
9576f613 772 const uint64_t SECONDS_BETWEEN_1601_AND_1970 = 11644473600;
9277ec14
BC
773 FILETIME cTime, eTime, kTime, uTime;
774 time_t time;
7732a09b 775 HANDLE h;
9277ec14
BC
776
777 memset(r_usage, 0, sizeof(*r_usage));
778
7732a09b
HL
779 if (who == RUSAGE_SELF) {
780 h = GetCurrentProcess();
781 GetProcessTimes(h, &cTime, &eTime, &kTime, &uTime);
782 } else if (who == RUSAGE_THREAD) {
783 h = GetCurrentThread();
784 GetThreadTimes(h, &cTime, &eTime, &kTime, &uTime);
785 } else {
786 log_err("fio: getrusage %d is not implemented\n", who);
787 return -1;
788 }
789
9576f613 790 time = ((uint64_t)uTime.dwHighDateTime << 32) + uTime.dwLowDateTime;
9277ec14
BC
791 /* Divide by 10,000,000 to get the number of seconds and move the epoch from
792 * 1601 to 1970 */
793 time = (time_t)(((time)/10000000) - SECONDS_BETWEEN_1601_AND_1970);
794 r_usage->ru_utime.tv_sec = time;
795 /* getrusage() doesn't care about anything other than seconds, so set tv_usec to 0 */
796 r_usage->ru_utime.tv_usec = 0;
9576f613 797 time = ((uint64_t)kTime.dwHighDateTime << 32) + kTime.dwLowDateTime;
9277ec14
BC
798 /* Divide by 10,000,000 to get the number of seconds and move the epoch from
799 * 1601 to 1970 */
800 time = (time_t)(((time)/10000000) - SECONDS_BETWEEN_1601_AND_1970);
801 r_usage->ru_stime.tv_sec = time;
802 r_usage->ru_stime.tv_usec = 0;
803 return 0;
804}
805
806int posix_madvise(void *addr, size_t len, int advice)
807{
9277ec14
BC
808 return ENOSYS;
809}
810
9277ec14
BC
811int fdatasync(int fildes)
812{
813 return fsync(fildes);
814}
815
816ssize_t pwrite(int fildes, const void *buf, size_t nbyte,
817 off_t offset)
818{
9576f613
BC
819 int64_t pos = _telli64(fildes);
820 ssize_t len = _write(fildes, buf, nbyte);
e8ed50bc 821
9576f613 822 _lseeki64(fildes, pos, SEEK_SET);
9277ec14
BC
823 return len;
824}
825
826ssize_t pread(int fildes, void *buf, size_t nbyte, off_t offset)
827{
9576f613 828 int64_t pos = _telli64(fildes);
9277ec14 829 ssize_t len = read(fildes, buf, nbyte);
e8ed50bc 830
9576f613 831 _lseeki64(fildes, pos, SEEK_SET);
9277ec14
BC
832 return len;
833}
834
835ssize_t readv(int fildes, const struct iovec *iov, int iovcnt)
836{
837 log_err("%s is not implemented\n", __func__);
838 errno = ENOSYS;
10a6b3c6 839 return -1;
9277ec14
BC
840}
841
842ssize_t writev(int fildes, const struct iovec *iov, int iovcnt)
843{
70a61165
BC
844 int i;
845 DWORD bytes_written = 0;
e8ed50bc
JA
846
847 for (i = 0; i < iovcnt; i++) {
848 int len;
849
850 len = send((SOCKET)fildes, iov[i].iov_base, iov[i].iov_len, 0);
851 if (len == SOCKET_ERROR) {
70a61165
BC
852 DWORD err = GetLastError();
853 errno = win_to_posix_error(err);
854 bytes_written = -1;
855 break;
856 }
857 bytes_written += len;
858 }
859
860 return bytes_written;
9277ec14
BC
861}
862
e8ed50bc 863long long strtoll(const char *restrict str, char **restrict endptr, int base)
9277ec14
BC
864{
865 return _strtoi64(str, endptr, base);
866}
867
9277ec14
BC
868int poll(struct pollfd fds[], nfds_t nfds, int timeout)
869{
870 struct timeval tv;
871 struct timeval *to = NULL;
872 fd_set readfds, writefds, exceptfds;
873 int i;
874 int rc;
875
3f457bea 876 if (timeout != -1) {
f9a58c2a 877 to = &tv;
3f457bea
BC
878 to->tv_sec = timeout / 1000;
879 to->tv_usec = (timeout % 1000) * 1000;
880 }
9277ec14
BC
881
882 FD_ZERO(&readfds);
883 FD_ZERO(&writefds);
884 FD_ZERO(&exceptfds);
885
e8ed50bc 886 for (i = 0; i < nfds; i++) {
2ec7cd03 887 if (fds[i].fd == INVALID_SOCKET) {
9277ec14
BC
888 fds[i].revents = 0;
889 continue;
890 }
891
892 if (fds[i].events & POLLIN)
893 FD_SET(fds[i].fd, &readfds);
894
895 if (fds[i].events & POLLOUT)
896 FD_SET(fds[i].fd, &writefds);
897
f9a58c2a 898 FD_SET(fds[i].fd, &exceptfds);
9277ec14 899 }
9277ec14
BC
900 rc = select(nfds, &readfds, &writefds, &exceptfds, to);
901
902 if (rc != SOCKET_ERROR) {
e8ed50bc 903 for (i = 0; i < nfds; i++) {
2ec7cd03 904 if (fds[i].fd == INVALID_SOCKET)
9277ec14 905 continue;
9277ec14
BC
906
907 if ((fds[i].events & POLLIN) && FD_ISSET(fds[i].fd, &readfds))
908 fds[i].revents |= POLLIN;
909
910 if ((fds[i].events & POLLOUT) && FD_ISSET(fds[i].fd, &writefds))
911 fds[i].revents |= POLLOUT;
912
913 if (FD_ISSET(fds[i].fd, &exceptfds))
914 fds[i].revents |= POLLHUP;
915 }
916 }
9277ec14
BC
917 return rc;
918}
919
920int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
921{
8b6a404c 922 struct timespec tv;
21c75387
BC
923 DWORD ms_remaining;
924 DWORD ms_total = (rqtp->tv_sec * 1000) + (rqtp->tv_nsec / 1000000.0);
925
926 if (ms_total == 0)
927 ms_total = 1;
928
929 ms_remaining = ms_total;
930
931 /* Since Sleep() can sleep for less than the requested time, add a loop to
932 ensure we only return after the requested length of time has elapsed */
933 do {
934 fio_gettime(&tv, NULL);
935 Sleep(ms_remaining);
936 ms_remaining = ms_total - mtime_since_now(&tv);
937 } while (ms_remaining > 0 && ms_remaining < ms_total);
938
939 /* this implementation will never sleep for less than the requested time */
940 if (rmtp != NULL) {
941 rmtp->tv_sec = 0;
942 rmtp->tv_nsec = 0;
943 }
944
945 return 0;
9277ec14
BC
946}
947
948DIR *opendir(const char *dirname)
949{
01d26955 950 struct dirent_ctx *dc = NULL;
e8ed50bc 951 HANDLE file;
01d26955
BC
952
953 /* See if we can open it. If not, we'll return an error here */
e8ed50bc
JA
954 file = CreateFileA(dirname, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
955 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
01d26955
BC
956 if (file != INVALID_HANDLE_VALUE) {
957 CloseHandle(file);
a4820445
BVA
958 dc = malloc(sizeof(struct dirent_ctx));
959 snprintf(dc->dirname, sizeof(dc->dirname), "%s", dirname);
01d26955
BC
960 dc->find_handle = INVALID_HANDLE_VALUE;
961 } else {
962 DWORD error = GetLastError();
963 if (error == ERROR_FILE_NOT_FOUND)
964 errno = ENOENT;
965
966 else if (error == ERROR_PATH_NOT_FOUND)
967 errno = ENOTDIR;
968 else if (error == ERROR_TOO_MANY_OPEN_FILES)
969 errno = ENFILE;
970 else if (error == ERROR_ACCESS_DENIED)
971 errno = EACCES;
972 else
973 errno = error;
974 }
975
976 return dc;
9277ec14
BC
977}
978
979int closedir(DIR *dirp)
980{
01d26955
BC
981 if (dirp != NULL && dirp->find_handle != INVALID_HANDLE_VALUE)
982 FindClose(dirp->find_handle);
ad9c0fbc 983
01d26955
BC
984 free(dirp);
985 return 0;
9277ec14
BC
986}
987
988struct dirent *readdir(DIR *dirp)
989{
ad9c0fbc
BC
990 static struct dirent de;
991 WIN32_FIND_DATA find_data;
992
993 if (dirp == NULL)
994 return NULL;
995
996 if (dirp->find_handle == INVALID_HANDLE_VALUE) {
997 char search_pattern[MAX_PATH];
e8ed50bc 998
a4820445
BVA
999 snprintf(search_pattern, sizeof(search_pattern), "%s\\*",
1000 dirp->dirname);
ad9c0fbc
BC
1001 dirp->find_handle = FindFirstFileA(search_pattern, &find_data);
1002 if (dirp->find_handle == INVALID_HANDLE_VALUE)
1003 return NULL;
1004 } else {
1005 if (!FindNextFile(dirp->find_handle, &find_data))
1006 return NULL;
1007 }
1008
a4820445 1009 snprintf(de.d_name, sizeof(de.d_name), find_data.cFileName);
ad9c0fbc
BC
1010 de.d_ino = 0;
1011
1012 return &de;
9277ec14
BC
1013}
1014
1015uid_t geteuid(void)
1016{
1017 log_err("%s is not implemented\n", __func__);
1018 errno = ENOSYS;
1019 return -1;
1020}
1021
f16b7405
BC
1022in_addr_t inet_network(const char *cp)
1023{
1024 in_addr_t hbo;
1025 in_addr_t nbo = inet_addr(cp);
1026 hbo = ((nbo & 0xFF) << 24) + ((nbo & 0xFF00) << 8) + ((nbo & 0xFF0000) >> 8) + ((nbo & 0xFF000000) >> 24);
1027 return hbo;
1028}