Merge branch 'esx-timerfd-bypass' of https://github.com/brianredbeard/fio
[fio.git] / os / windows / posix.c
... / ...
CommitLineData
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>
10#include <string.h>
11#include <stdlib.h>
12#include <unistd.h>
13#include <dirent.h>
14#include <pthread.h>
15#include <time.h>
16#include <semaphore.h>
17#include <sys/shm.h>
18#include <sys/mman.h>
19#include <sys/uio.h>
20#include <sys/resource.h>
21#include <poll.h>
22#include <sys/wait.h>
23#include <setjmp.h>
24
25#include "../os-windows.h"
26#include "../../lib/hweight.h"
27
28extern unsigned long mtime_since_now(struct timespec *);
29extern void fio_gettime(struct timespec *, void *);
30
31int win_to_posix_error(DWORD winerr)
32{
33 switch (winerr) {
34 case ERROR_SUCCESS:
35 return 0;
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;
170 default:
171 log_err("fio: windows error %lu not handled\n", winerr);
172 return EIO;
173 }
174
175 return winerr;
176}
177
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 {
191 log_err("Error: GetLogicalProcessorInformation failed: %lu\n",
192 error);
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
202 for (i = 0; i < len / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); i++) {
203 if (processor_info[i].Relationship == RelationProcessorCore)
204 num_processors += hweight64(processor_info[i].ProcessorMask);
205 }
206
207 free(processor_info);
208 return num_processors;
209}
210
211long sysconf(int name)
212{
213 long val = -1;
214 long val2 = -1;
215 SYSTEM_INFO sysInfo;
216 MEMORYSTATUSEX status;
217
218 switch (name) {
219 case _SC_NPROCESSORS_ONLN:
220 val = GetNumLogicalProcessors();
221 if (val == -1)
222 log_err("sysconf(_SC_NPROCESSORS_ONLN) failed\n");
223
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);
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");
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
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{
288 FILETIME utcFT;
289 LONGLONG jan1970;
290 SYSTEMTIME tempSystemTime;
291
292 jan1970 = Int32x32To64(dosTime, 10000000) + 116444736000000000;
293 utcFT.dwLowDateTime = (DWORD)jan1970;
294 utcFT.dwHighDateTime = jan1970 >> 32;
295
296 FileTimeToSystemTime((FILETIME*)&utcFT, &tempSystemTime);
297 SystemTimeToTzSpecificLocalTime(NULL, &tempSystemTime, systemTime);
298}
299
300char *ctime_r(const time_t *t, char *buf)
301{
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 */
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);
317 return buf;
318}
319
320int gettimeofday(struct timeval *restrict tp, void *restrict tzp)
321{
322 FILETIME fileTime;
323 uint64_t unix_time, windows_time;
324 const uint64_t MILLISECONDS_BETWEEN_1601_AND_1970 = 11644473600000;
325
326 /* Ignore the timezone parameter */
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);
335 windows_time = ((uint64_t)fileTime.dwHighDateTime << 32) + fileTime.dwLowDateTime;
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
344int sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
345{
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;
357}
358
359int lstat(const char *path, struct stat *buf)
360{
361 return stat(path, buf);
362}
363
364void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off)
365{
366 DWORD vaProt = 0;
367 DWORD mapAccess = 0;
368 DWORD lenlow;
369 DWORD lenhigh;
370 HANDLE hMap;
371 void* allocAddr = NULL;
372
373 if (prot & PROT_NONE)
374 vaProt |= PAGE_NOACCESS;
375
376 if ((prot & PROT_READ) && !(prot & PROT_WRITE)) {
377 vaProt |= PAGE_READONLY;
378 mapAccess = FILE_MAP_READ;
379 }
380
381 if (prot & PROT_WRITE) {
382 vaProt |= PAGE_READWRITE;
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. */
390 if (lenlow == 0)
391 lenhigh = 0;
392
393 if (flags & MAP_ANON || flags & MAP_ANONYMOUS) {
394 allocAddr = VirtualAlloc(addr, len, MEM_COMMIT, vaProt);
395 if (allocAddr == NULL)
396 errno = win_to_posix_error(GetLastError());
397 } else {
398 hMap = CreateFileMapping((HANDLE)_get_osfhandle(fildes), NULL,
399 vaProt, lenhigh, lenlow, NULL);
400
401 if (hMap != NULL)
402 allocAddr = MapViewOfFile(hMap, mapAccess, off >> 16,
403 off & 0xFFFF, len);
404 if (hMap == NULL || allocAddr == NULL)
405 errno = win_to_posix_error(GetLastError());
406
407 }
408
409 return allocAddr;
410}
411
412int munmap(void *addr, size_t len)
413{
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)
422 success = VirtualFree(addr, 0, MEM_RELEASE);
423
424 return !success;
425}
426
427int msync(void *addr, size_t len, int flags)
428{
429 return !FlushViewOfFile(addr, len);
430}
431
432int fork(void)
433{
434 log_err("%s is not implemented\n", __func__);
435 errno = ENOSYS;
436 return -1;
437}
438
439pid_t setsid(void)
440{
441 log_err("%s is not implemented\n", __func__);
442 errno = ENOSYS;
443 return -1;
444}
445
446static HANDLE log_file = INVALID_HANDLE_VALUE;
447
448void openlog(const char *ident, int logopt, int facility)
449{
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);
456}
457
458void closelog(void)
459{
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) {
472 log_file = CreateFileA("syslog.txt", GENERIC_WRITE,
473 FILE_SHARE_READ | FILE_SHARE_WRITE,
474 NULL, OPEN_ALWAYS, 0, NULL);
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));
485 vsprintf(output, message, v);
486 WriteFile(log_file, output, len, &bytes_written, NULL);
487 va_end(v);
488 free(output);
489}
490
491int kill(pid_t pid, int sig)
492{
493 errno = ESRCH;
494 return -1;
495}
496
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 */
501int fcntl(int fildes, int cmd, ...)
502{
503 /*
504 * non-blocking mode doesn't work the same as in BSD sockets,
505 * so ignore it.
506 */
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;
515 return -1;
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
549 if (clock_id == CLOCK_MONOTONIC) {
550 static LARGE_INTEGER freq = {{0,0}};
551 LARGE_INTEGER counts;
552 uint64_t t;
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' */
561 t = tp->tv_sec * freq.QuadPart;
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;
568 } else if (clock_id == CLOCK_REALTIME) {
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{
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;
610}
611
612int munlock(const void * addr, size_t len)
613{
614 BOOL success = VirtualUnlock((LPVOID)addr, len);
615
616 if (!success) {
617 errno = win_to_posix_error(GetLastError());
618 return -1;
619 }
620
621 return 0;
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
647 while (path[i] != '\\' && path[i] != '/' && i >= 0)
648 i--;
649
650 name[MAX_PATH - 1] = '\0';
651 strncpy(name, path + i + 1, MAX_PATH - 1);
652
653 return name;
654}
655
656int fsync(int fildes)
657{
658 HANDLE hFile = (HANDLE)_get_osfhandle(fildes);
659 if (!FlushFileBuffers(hFile)) {
660 errno = win_to_posix_error(GetLastError());
661 return -1;
662 }
663
664 return 0;
665}
666
667int nFileMappings = 0;
668HANDLE fileMappings[1024];
669
670int shmget(key_t key, size_t size, int shmflg)
671{
672 int mapid = -1;
673 uint32_t size_low = size & 0xFFFFFFFF;
674 uint32_t size_high = ((uint64_t)size) >> 32;
675 HANDLE hMapping;
676
677 hMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
678 PAGE_EXECUTE_READWRITE | SEC_RESERVE,
679 size_high, size_low, NULL);
680 if (hMapping != NULL) {
681 fileMappings[nFileMappings] = hMapping;
682 mapid = nFileMappings;
683 nFileMappings++;
684 } else
685 errno = ENOSYS;
686
687 return mapid;
688}
689
690void *shmat(int shmid, const void *shmaddr, int shmflg)
691{
692 void *mapAddr;
693 MEMORY_BASIC_INFORMATION memInfo;
694
695 mapAddr = MapViewOfFile(fileMappings[shmid], FILE_MAP_ALL_ACCESS, 0, 0, 0);
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
706 mapAddr = VirtualAlloc(mapAddr, memInfo.RegionSize, MEM_COMMIT, PAGE_READWRITE);
707 if (mapAddr == NULL) {
708 errno = win_to_posix_error(GetLastError());
709 return (void*)-1;
710 }
711
712 return mapAddr;
713}
714
715int shmdt(const void *shmaddr)
716{
717 if (!UnmapViewOfFile(shmaddr)) {
718 errno = win_to_posix_error(GetLastError());
719 return -1;
720 }
721
722 return 0;
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;
730 }
731
732 log_err("%s is not implemented\n", __func__);
733 errno = ENOSYS;
734 return -1;
735}
736
737int setuid(uid_t uid)
738{
739 log_err("%s is not implemented\n", __func__);
740 errno = ENOSYS;
741 return -1;
742}
743
744int setgid(gid_t gid)
745{
746 log_err("%s is not implemented\n", __func__);
747 errno = ENOSYS;
748 return -1;
749}
750
751int nice(int incr)
752{
753 DWORD prioclass = NORMAL_PRIORITY_CLASS;
754
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;
763
764 if (!SetPriorityClass(GetCurrentProcess(), prioclass))
765 log_err("fio: SetPriorityClass failed\n");
766
767 return 0;
768}
769
770int getrusage(int who, struct rusage *r_usage)
771{
772 const uint64_t SECONDS_BETWEEN_1601_AND_1970 = 11644473600;
773 FILETIME cTime, eTime, kTime, uTime;
774 time_t time;
775 HANDLE h;
776
777 memset(r_usage, 0, sizeof(*r_usage));
778
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
790 time = ((uint64_t)uTime.dwHighDateTime << 32) + uTime.dwLowDateTime;
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;
797 time = ((uint64_t)kTime.dwHighDateTime << 32) + kTime.dwLowDateTime;
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{
808 return ENOSYS;
809}
810
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{
819 int64_t pos = _telli64(fildes);
820 ssize_t len = _write(fildes, buf, nbyte);
821
822 _lseeki64(fildes, pos, SEEK_SET);
823 return len;
824}
825
826ssize_t pread(int fildes, void *buf, size_t nbyte, off_t offset)
827{
828 int64_t pos = _telli64(fildes);
829 ssize_t len = read(fildes, buf, nbyte);
830
831 _lseeki64(fildes, pos, SEEK_SET);
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;
839 return -1;
840}
841
842ssize_t writev(int fildes, const struct iovec *iov, int iovcnt)
843{
844 int i;
845 DWORD bytes_written = 0;
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) {
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;
861}
862
863long long strtoll(const char *restrict str, char **restrict endptr, int base)
864{
865 return _strtoi64(str, endptr, base);
866}
867
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
876 if (timeout != -1) {
877 to = &tv;
878 to->tv_sec = timeout / 1000;
879 to->tv_usec = (timeout % 1000) * 1000;
880 }
881
882 FD_ZERO(&readfds);
883 FD_ZERO(&writefds);
884 FD_ZERO(&exceptfds);
885
886 for (i = 0; i < nfds; i++) {
887 if (fds[i].fd == INVALID_SOCKET) {
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
898 FD_SET(fds[i].fd, &exceptfds);
899 }
900 rc = select(nfds, &readfds, &writefds, &exceptfds, to);
901
902 if (rc != SOCKET_ERROR) {
903 for (i = 0; i < nfds; i++) {
904 if (fds[i].fd == INVALID_SOCKET)
905 continue;
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 }
917 return rc;
918}
919
920int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
921{
922 struct timespec tv;
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;
946}
947
948DIR *opendir(const char *dirname)
949{
950 struct dirent_ctx *dc = NULL;
951 HANDLE file;
952
953 /* See if we can open it. If not, we'll return an error here */
954 file = CreateFileA(dirname, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
955 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
956 if (file != INVALID_HANDLE_VALUE) {
957 CloseHandle(file);
958 dc = malloc(sizeof(struct dirent_ctx));
959 snprintf(dc->dirname, sizeof(dc->dirname), "%s", dirname);
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;
977}
978
979int closedir(DIR *dirp)
980{
981 if (dirp != NULL && dirp->find_handle != INVALID_HANDLE_VALUE)
982 FindClose(dirp->find_handle);
983
984 free(dirp);
985 return 0;
986}
987
988struct dirent *readdir(DIR *dirp)
989{
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];
998
999 snprintf(search_pattern, sizeof(search_pattern), "%s\\*",
1000 dirp->dirname);
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
1009 snprintf(de.d_name, sizeof(de.d_name), find_data.cFileName);
1010 de.d_ino = 0;
1011
1012 return &de;
1013}
1014
1015uid_t geteuid(void)
1016{
1017 log_err("%s is not implemented\n", __func__);
1018 errno = ENOSYS;
1019 return -1;
1020}
1021
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}