t/nvmept_trim: increase transfer size for some tests
[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_CONF:
220 /*
221 * Using GetMaximumProcessorCount introduces a problem in
222 * gettime.c because Windows does not have
223 * fio_get_thread_affinity. Log sample (see #1479):
224 *
225 * CPU mask contains processor beyond last active processor index (2)
226 * clock setaffinity failed: No error
227 */
228 val = GetActiveProcessorCount(ALL_PROCESSOR_GROUPS);
229 if (val == -1)
230 log_err("sysconf(_SC_NPROCESSORS_CONF) failed\n");
231
232 break;
233
234 case _SC_PAGESIZE:
235 GetSystemInfo(&sysInfo);
236 val = sysInfo.dwPageSize;
237 break;
238
239 case _SC_PHYS_PAGES:
240 status.dwLength = sizeof(status);
241 val2 = sysconf(_SC_PAGESIZE);
242 if (GlobalMemoryStatusEx(&status) && val2 != -1)
243 val = status.ullTotalPhys / val2;
244 else
245 log_err("sysconf(_SC_PHYS_PAGES) failed\n");
246 break;
247 default:
248 log_err("sysconf(%d) is not implemented\n", name);
249 break;
250 }
251
252 return val;
253}
254
255char *dl_error = NULL;
256
257int dlclose(void *handle)
258{
259 return !FreeLibrary((HMODULE)handle);
260}
261
262void *dlopen(const char *file, int mode)
263{
264 HMODULE hMod;
265
266 hMod = LoadLibrary(file);
267 if (hMod == INVALID_HANDLE_VALUE)
268 dl_error = (char*)"LoadLibrary failed";
269 else
270 dl_error = NULL;
271
272 return hMod;
273}
274
275void *dlsym(void *handle, const char *name)
276{
277 FARPROC fnPtr;
278
279 fnPtr = GetProcAddress((HMODULE)handle, name);
280 if (fnPtr == NULL)
281 dl_error = (char*)"GetProcAddress failed";
282 else
283 dl_error = NULL;
284
285 return fnPtr;
286}
287
288char *dlerror(void)
289{
290 return dl_error;
291}
292
293/* Copied from http://blogs.msdn.com/b/joshpoley/archive/2007/12/19/date-time-formats-and-conversions.aspx */
294void Time_tToSystemTime(time_t dosTime, SYSTEMTIME *systemTime)
295{
296 FILETIME utcFT;
297 LONGLONG jan1970;
298 SYSTEMTIME tempSystemTime;
299
300 jan1970 = Int32x32To64(dosTime, 10000000) + 116444736000000000;
301 utcFT.dwLowDateTime = (DWORD)jan1970;
302 utcFT.dwHighDateTime = jan1970 >> 32;
303
304 FileTimeToSystemTime((FILETIME*)&utcFT, &tempSystemTime);
305 SystemTimeToTzSpecificLocalTime(NULL, &tempSystemTime, systemTime);
306}
307
308char *ctime_r(const time_t *t, char *buf)
309{
310 SYSTEMTIME systime;
311 const char * const dayOfWeek[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" };
312 const char * const monthOfYear[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
313
314 Time_tToSystemTime(*t, &systime);
315
316 /*
317 * We don't know how long `buf` is, but assume it's rounded up from
318 * the minimum of 25 to 32
319 */
320 snprintf(buf, 32, "%s %s %d %02d:%02d:%02d %04d\n",
321 dayOfWeek[systime.wDayOfWeek % 7],
322 monthOfYear[(systime.wMonth - 1) % 12],
323 systime.wDay, systime.wHour, systime.wMinute,
324 systime.wSecond, systime.wYear);
325 return buf;
326}
327
328int gettimeofday(struct timeval *restrict tp, void *restrict tzp)
329{
330 FILETIME fileTime;
331 uint64_t unix_time, windows_time;
332 const uint64_t MILLISECONDS_BETWEEN_1601_AND_1970 = 11644473600000;
333
334 /* Ignore the timezone parameter */
335 (void)tzp;
336
337 /*
338 * Windows time is stored as the number 100 ns intervals since January 1 1601.
339 * Conversion details from http://www.informit.com/articles/article.aspx?p=102236&seqNum=3
340 * Its precision is 100 ns but accuracy is only one clock tick, or normally around 15 ms.
341 */
342 GetSystemTimeAsFileTime(&fileTime);
343 windows_time = ((uint64_t)fileTime.dwHighDateTime << 32) + fileTime.dwLowDateTime;
344 /* Divide by 10,000 to convert to ms and subtract the time between 1601 and 1970 */
345 unix_time = (((windows_time)/10000) - MILLISECONDS_BETWEEN_1601_AND_1970);
346 /* unix_time is now the number of milliseconds since 1970 (the Unix epoch) */
347 tp->tv_sec = unix_time / 1000;
348 tp->tv_usec = (unix_time % 1000) * 1000;
349 return 0;
350}
351
352int sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
353{
354 int rc = 0;
355 void (*prev_handler)(int);
356
357 prev_handler = signal(sig, act->sa_handler);
358 if (oact != NULL)
359 oact->sa_handler = prev_handler;
360
361 if (prev_handler == SIG_ERR)
362 rc = -1;
363
364 return rc;
365}
366
367int lstat(const char *path, struct stat *buf)
368{
369 return stat(path, buf);
370}
371
372void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off)
373{
374 DWORD vaProt = 0;
375 DWORD mapAccess = 0;
376 DWORD lenlow;
377 DWORD lenhigh;
378 HANDLE hMap;
379 void* allocAddr = NULL;
380
381 if (prot & PROT_NONE)
382 vaProt |= PAGE_NOACCESS;
383
384 if ((prot & PROT_READ) && !(prot & PROT_WRITE)) {
385 vaProt |= PAGE_READONLY;
386 mapAccess = FILE_MAP_READ;
387 }
388
389 if (prot & PROT_WRITE) {
390 vaProt |= PAGE_READWRITE;
391 mapAccess |= FILE_MAP_WRITE;
392 }
393
394 lenlow = len & 0xFFFF;
395 lenhigh = len >> 16;
396 /* If the low DWORD is zero and the high DWORD is non-zero, `CreateFileMapping`
397 will return ERROR_INVALID_PARAMETER. To avoid this, set both to zero. */
398 if (lenlow == 0)
399 lenhigh = 0;
400
401 if (flags & MAP_ANON || flags & MAP_ANONYMOUS) {
402 allocAddr = VirtualAlloc(addr, len, MEM_COMMIT, vaProt);
403 if (allocAddr == NULL)
404 errno = win_to_posix_error(GetLastError());
405 } else {
406 hMap = CreateFileMapping((HANDLE)_get_osfhandle(fildes), NULL,
407 vaProt, lenhigh, lenlow, NULL);
408
409 if (hMap != NULL)
410 allocAddr = MapViewOfFile(hMap, mapAccess, off >> 16,
411 off & 0xFFFF, len);
412 if (hMap == NULL || allocAddr == NULL)
413 errno = win_to_posix_error(GetLastError());
414
415 }
416
417 return allocAddr;
418}
419
420int munmap(void *addr, size_t len)
421{
422 BOOL success;
423
424 /* We may have allocated the memory with either MapViewOfFile or
425 VirtualAlloc. Therefore, try calling UnmapViewOfFile first, and if that
426 fails, call VirtualFree. */
427 success = UnmapViewOfFile(addr);
428
429 if (!success)
430 success = VirtualFree(addr, 0, MEM_RELEASE);
431
432 return !success;
433}
434
435int msync(void *addr, size_t len, int flags)
436{
437 return !FlushViewOfFile(addr, len);
438}
439
440int fork(void)
441{
442 log_err("%s is not implemented\n", __func__);
443 errno = ENOSYS;
444 return -1;
445}
446
447pid_t setsid(void)
448{
449 log_err("%s is not implemented\n", __func__);
450 errno = ENOSYS;
451 return -1;
452}
453
454static HANDLE log_file = INVALID_HANDLE_VALUE;
455
456void openlog(const char *ident, int logopt, int facility)
457{
458 if (log_file != INVALID_HANDLE_VALUE)
459 return;
460
461 log_file = CreateFileA("syslog.txt", GENERIC_WRITE,
462 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
463 OPEN_ALWAYS, 0, NULL);
464}
465
466void closelog(void)
467{
468 CloseHandle(log_file);
469 log_file = INVALID_HANDLE_VALUE;
470}
471
472void syslog(int priority, const char *message, ... /* argument */)
473{
474 va_list v;
475 int len;
476 char *output;
477 DWORD bytes_written;
478
479 if (log_file == INVALID_HANDLE_VALUE) {
480 log_file = CreateFileA("syslog.txt", GENERIC_WRITE,
481 FILE_SHARE_READ | FILE_SHARE_WRITE,
482 NULL, OPEN_ALWAYS, 0, NULL);
483 }
484
485 if (log_file == INVALID_HANDLE_VALUE) {
486 log_err("syslog: failed to open log file\n");
487 return;
488 }
489
490 va_start(v, message);
491 len = _vscprintf(message, v);
492 output = malloc(len + sizeof(char));
493 vsprintf(output, message, v);
494 WriteFile(log_file, output, len, &bytes_written, NULL);
495 va_end(v);
496 free(output);
497}
498
499int kill(pid_t pid, int sig)
500{
501 errno = ESRCH;
502 return -1;
503}
504
505/*
506 * This is assumed to be used only by the network code,
507 * and so doesn't try and handle any of the other cases
508 */
509int fcntl(int fildes, int cmd, ...)
510{
511 /*
512 * non-blocking mode doesn't work the same as in BSD sockets,
513 * so ignore it.
514 */
515#if 0
516 va_list ap;
517 int val, opt, status;
518
519 if (cmd == F_GETFL)
520 return 0;
521 else if (cmd != F_SETFL) {
522 errno = EINVAL;
523 return -1;
524 }
525
526 va_start(ap, 1);
527
528 opt = va_arg(ap, int);
529 if (opt & O_NONBLOCK)
530 val = 1;
531 else
532 val = 0;
533
534 status = ioctlsocket((SOCKET)fildes, opt, &val);
535
536 if (status == SOCKET_ERROR) {
537 errno = EINVAL;
538 val = -1;
539 }
540
541 va_end(ap);
542
543 return val;
544#endif
545return 0;
546}
547
548#ifndef CLOCK_MONOTONIC_RAW
549#define CLOCK_MONOTONIC_RAW 4
550#endif
551
552/*
553 * Get the value of a local clock source.
554 * This implementation supports 3 clocks: CLOCK_MONOTONIC/CLOCK_MONOTONIC_RAW
555 * provide high-accuracy relative time, while CLOCK_REALTIME provides a
556 * low-accuracy wall time.
557 */
558int clock_gettime(clockid_t clock_id, struct timespec *tp)
559{
560 int rc = 0;
561
562 if (clock_id == CLOCK_MONOTONIC || clock_id == CLOCK_MONOTONIC_RAW) {
563 static LARGE_INTEGER freq = {{0,0}};
564 LARGE_INTEGER counts;
565 uint64_t t;
566
567 QueryPerformanceCounter(&counts);
568 if (freq.QuadPart == 0)
569 QueryPerformanceFrequency(&freq);
570
571 tp->tv_sec = counts.QuadPart / freq.QuadPart;
572 /* Get the difference between the number of ns stored
573 * in 'tv_sec' and that stored in 'counts' */
574 t = tp->tv_sec * freq.QuadPart;
575 t = counts.QuadPart - t;
576 /* 't' now contains the number of cycles since the last second.
577 * We want the number of nanoseconds, so multiply out by 1,000,000,000
578 * and then divide by the frequency. */
579 t *= 1000000000;
580 tp->tv_nsec = t / freq.QuadPart;
581 } else if (clock_id == CLOCK_REALTIME) {
582 /* clock_gettime(CLOCK_REALTIME,...) is just an alias for gettimeofday with a
583 * higher-precision field. */
584 struct timeval tv;
585 gettimeofday(&tv, NULL);
586 tp->tv_sec = tv.tv_sec;
587 tp->tv_nsec = tv.tv_usec * 1000;
588 } else {
589 errno = EINVAL;
590 rc = -1;
591 }
592
593 return rc;
594}
595
596int mlock(const void * addr, size_t len)
597{
598 SIZE_T min, max;
599 BOOL success;
600 HANDLE process = GetCurrentProcess();
601
602 success = GetProcessWorkingSetSize(process, &min, &max);
603 if (!success) {
604 errno = win_to_posix_error(GetLastError());
605 return -1;
606 }
607
608 min += len;
609 max += len;
610 success = SetProcessWorkingSetSize(process, min, max);
611 if (!success) {
612 errno = win_to_posix_error(GetLastError());
613 return -1;
614 }
615
616 success = VirtualLock((LPVOID)addr, len);
617 if (!success) {
618 errno = win_to_posix_error(GetLastError());
619 return -1;
620 }
621
622 return 0;
623}
624
625int munlock(const void * addr, size_t len)
626{
627 BOOL success = VirtualUnlock((LPVOID)addr, len);
628
629 if (!success) {
630 errno = win_to_posix_error(GetLastError());
631 return -1;
632 }
633
634 return 0;
635}
636
637pid_t waitpid(pid_t pid, int *stat_loc, int options)
638{
639 log_err("%s is not implemented\n", __func__);
640 errno = ENOSYS;
641 return -1;
642}
643
644int usleep(useconds_t useconds)
645{
646 Sleep(useconds / 1000);
647 return 0;
648}
649
650char *basename(char *path)
651{
652 static char name[MAX_PATH];
653 int i;
654
655 if (path == NULL || strlen(path) == 0)
656 return (char*)".";
657
658 i = strlen(path) - 1;
659
660 while (path[i] != '\\' && path[i] != '/' && i >= 0)
661 i--;
662
663 name[MAX_PATH - 1] = '\0';
664 strncpy(name, path + i + 1, MAX_PATH - 1);
665
666 return name;
667}
668
669int fsync(int fildes)
670{
671 HANDLE hFile = (HANDLE)_get_osfhandle(fildes);
672 if (!FlushFileBuffers(hFile)) {
673 errno = win_to_posix_error(GetLastError());
674 return -1;
675 }
676
677 return 0;
678}
679
680int nFileMappings = 0;
681HANDLE fileMappings[1024];
682
683int shmget(key_t key, size_t size, int shmflg)
684{
685 int mapid = -1;
686 uint32_t size_low = size & 0xFFFFFFFF;
687 uint32_t size_high = ((uint64_t)size) >> 32;
688 HANDLE hMapping;
689
690 hMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL,
691 PAGE_EXECUTE_READWRITE | SEC_RESERVE,
692 size_high, size_low, NULL);
693 if (hMapping != NULL) {
694 fileMappings[nFileMappings] = hMapping;
695 mapid = nFileMappings;
696 nFileMappings++;
697 } else
698 errno = ENOSYS;
699
700 return mapid;
701}
702
703void *shmat(int shmid, const void *shmaddr, int shmflg)
704{
705 void *mapAddr;
706 MEMORY_BASIC_INFORMATION memInfo;
707
708 mapAddr = MapViewOfFile(fileMappings[shmid], FILE_MAP_ALL_ACCESS, 0, 0, 0);
709 if (mapAddr == NULL) {
710 errno = win_to_posix_error(GetLastError());
711 return (void*)-1;
712 }
713
714 if (VirtualQuery(mapAddr, &memInfo, sizeof(memInfo)) == 0) {
715 errno = win_to_posix_error(GetLastError());
716 return (void*)-1;
717 }
718
719 mapAddr = VirtualAlloc(mapAddr, memInfo.RegionSize, MEM_COMMIT, PAGE_READWRITE);
720 if (mapAddr == NULL) {
721 errno = win_to_posix_error(GetLastError());
722 return (void*)-1;
723 }
724
725 return mapAddr;
726}
727
728int shmdt(const void *shmaddr)
729{
730 if (!UnmapViewOfFile(shmaddr)) {
731 errno = win_to_posix_error(GetLastError());
732 return -1;
733 }
734
735 return 0;
736}
737
738int shmctl(int shmid, int cmd, struct shmid_ds *buf)
739{
740 if (cmd == IPC_RMID) {
741 fileMappings[shmid] = INVALID_HANDLE_VALUE;
742 return 0;
743 }
744
745 log_err("%s is not implemented\n", __func__);
746 errno = ENOSYS;
747 return -1;
748}
749
750int setuid(uid_t uid)
751{
752 log_err("%s is not implemented\n", __func__);
753 errno = ENOSYS;
754 return -1;
755}
756
757int setgid(gid_t gid)
758{
759 log_err("%s is not implemented\n", __func__);
760 errno = ENOSYS;
761 return -1;
762}
763
764int nice(int incr)
765{
766 DWORD prioclass = NORMAL_PRIORITY_CLASS;
767
768 if (incr < -15)
769 prioclass = HIGH_PRIORITY_CLASS;
770 else if (incr < 0)
771 prioclass = ABOVE_NORMAL_PRIORITY_CLASS;
772 else if (incr > 15)
773 prioclass = IDLE_PRIORITY_CLASS;
774 else if (incr > 0)
775 prioclass = BELOW_NORMAL_PRIORITY_CLASS;
776
777 if (!SetPriorityClass(GetCurrentProcess(), prioclass))
778 log_err("fio: SetPriorityClass failed\n");
779
780 return 0;
781}
782
783int getrusage(int who, struct rusage *r_usage)
784{
785 const uint64_t SECONDS_BETWEEN_1601_AND_1970 = 11644473600;
786 FILETIME cTime, eTime, kTime, uTime;
787 time_t time;
788 HANDLE h;
789
790 memset(r_usage, 0, sizeof(*r_usage));
791
792 if (who == RUSAGE_SELF) {
793 h = GetCurrentProcess();
794 GetProcessTimes(h, &cTime, &eTime, &kTime, &uTime);
795 } else if (who == RUSAGE_THREAD) {
796 h = GetCurrentThread();
797 GetThreadTimes(h, &cTime, &eTime, &kTime, &uTime);
798 } else {
799 log_err("fio: getrusage %d is not implemented\n", who);
800 return -1;
801 }
802
803 time = ((uint64_t)uTime.dwHighDateTime << 32) + uTime.dwLowDateTime;
804 /* Divide by 10,000,000 to get the number of seconds and move the epoch from
805 * 1601 to 1970 */
806 time = (time_t)(((time)/10000000) - SECONDS_BETWEEN_1601_AND_1970);
807 r_usage->ru_utime.tv_sec = time;
808 /* getrusage() doesn't care about anything other than seconds, so set tv_usec to 0 */
809 r_usage->ru_utime.tv_usec = 0;
810 time = ((uint64_t)kTime.dwHighDateTime << 32) + kTime.dwLowDateTime;
811 /* Divide by 10,000,000 to get the number of seconds and move the epoch from
812 * 1601 to 1970 */
813 time = (time_t)(((time)/10000000) - SECONDS_BETWEEN_1601_AND_1970);
814 r_usage->ru_stime.tv_sec = time;
815 r_usage->ru_stime.tv_usec = 0;
816 return 0;
817}
818
819int posix_madvise(void *addr, size_t len, int advice)
820{
821 return ENOSYS;
822}
823
824int fdatasync(int fildes)
825{
826 return fsync(fildes);
827}
828
829ssize_t pwrite(int fildes, const void *buf, size_t nbyte,
830 off_t offset)
831{
832 int64_t pos = _telli64(fildes);
833 ssize_t len = _write(fildes, buf, nbyte);
834
835 _lseeki64(fildes, pos, SEEK_SET);
836 return len;
837}
838
839ssize_t pread(int fildes, void *buf, size_t nbyte, off_t offset)
840{
841 int64_t pos = _telli64(fildes);
842 ssize_t len = read(fildes, buf, nbyte);
843
844 _lseeki64(fildes, pos, SEEK_SET);
845 return len;
846}
847
848ssize_t readv(int fildes, const struct iovec *iov, int iovcnt)
849{
850 log_err("%s is not implemented\n", __func__);
851 errno = ENOSYS;
852 return -1;
853}
854
855ssize_t writev(int fildes, const struct iovec *iov, int iovcnt)
856{
857 int i;
858 DWORD bytes_written = 0;
859
860 for (i = 0; i < iovcnt; i++) {
861 int len;
862
863 len = send((SOCKET)fildes, iov[i].iov_base, iov[i].iov_len, 0);
864 if (len == SOCKET_ERROR) {
865 DWORD err = GetLastError();
866 errno = win_to_posix_error(err);
867 bytes_written = -1;
868 break;
869 }
870 bytes_written += len;
871 }
872
873 return bytes_written;
874}
875
876long long strtoll(const char *restrict str, char **restrict endptr, int base)
877{
878 return _strtoi64(str, endptr, base);
879}
880
881int poll(struct pollfd fds[], nfds_t nfds, int timeout)
882{
883 struct timeval tv;
884 struct timeval *to = NULL;
885 fd_set readfds, writefds, exceptfds;
886 int i;
887 int rc;
888
889 if (timeout != -1) {
890 to = &tv;
891 to->tv_sec = timeout / 1000;
892 to->tv_usec = (timeout % 1000) * 1000;
893 }
894
895 FD_ZERO(&readfds);
896 FD_ZERO(&writefds);
897 FD_ZERO(&exceptfds);
898
899 for (i = 0; i < nfds; i++) {
900 if (fds[i].fd == INVALID_SOCKET) {
901 fds[i].revents = 0;
902 continue;
903 }
904
905 if (fds[i].events & POLLIN)
906 FD_SET(fds[i].fd, &readfds);
907
908 if (fds[i].events & POLLOUT)
909 FD_SET(fds[i].fd, &writefds);
910
911 FD_SET(fds[i].fd, &exceptfds);
912 }
913 rc = select(nfds, &readfds, &writefds, &exceptfds, to);
914
915 if (rc != SOCKET_ERROR) {
916 for (i = 0; i < nfds; i++) {
917 if (fds[i].fd == INVALID_SOCKET)
918 continue;
919
920 if ((fds[i].events & POLLIN) && FD_ISSET(fds[i].fd, &readfds))
921 fds[i].revents |= POLLIN;
922
923 if ((fds[i].events & POLLOUT) && FD_ISSET(fds[i].fd, &writefds))
924 fds[i].revents |= POLLOUT;
925
926 if (FD_ISSET(fds[i].fd, &exceptfds))
927 fds[i].revents |= POLLHUP;
928 }
929 }
930 return rc;
931}
932
933int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
934{
935 struct timespec tv;
936 DWORD ms_remaining;
937 DWORD ms_total = (rqtp->tv_sec * 1000) + (rqtp->tv_nsec / 1000000.0);
938
939 if (ms_total == 0)
940 ms_total = 1;
941
942 ms_remaining = ms_total;
943
944 /* Since Sleep() can sleep for less than the requested time, add a loop to
945 ensure we only return after the requested length of time has elapsed */
946 do {
947 fio_gettime(&tv, NULL);
948 Sleep(ms_remaining);
949 ms_remaining = ms_total - mtime_since_now(&tv);
950 } while (ms_remaining > 0 && ms_remaining < ms_total);
951
952 /* this implementation will never sleep for less than the requested time */
953 if (rmtp != NULL) {
954 rmtp->tv_sec = 0;
955 rmtp->tv_nsec = 0;
956 }
957
958 return 0;
959}
960
961DIR *opendir(const char *dirname)
962{
963 struct dirent_ctx *dc = NULL;
964 HANDLE file;
965
966 /* See if we can open it. If not, we'll return an error here */
967 file = CreateFileA(dirname, 0, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
968 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
969 if (file != INVALID_HANDLE_VALUE) {
970 CloseHandle(file);
971 dc = malloc(sizeof(struct dirent_ctx));
972 snprintf(dc->dirname, sizeof(dc->dirname), "%s", dirname);
973 dc->find_handle = INVALID_HANDLE_VALUE;
974 } else {
975 DWORD error = GetLastError();
976 if (error == ERROR_FILE_NOT_FOUND)
977 errno = ENOENT;
978
979 else if (error == ERROR_PATH_NOT_FOUND)
980 errno = ENOTDIR;
981 else if (error == ERROR_TOO_MANY_OPEN_FILES)
982 errno = ENFILE;
983 else if (error == ERROR_ACCESS_DENIED)
984 errno = EACCES;
985 else
986 errno = error;
987 }
988
989 return dc;
990}
991
992int closedir(DIR *dirp)
993{
994 if (dirp != NULL && dirp->find_handle != INVALID_HANDLE_VALUE)
995 FindClose(dirp->find_handle);
996
997 free(dirp);
998 return 0;
999}
1000
1001struct dirent *readdir(DIR *dirp)
1002{
1003 static struct dirent de;
1004 WIN32_FIND_DATA find_data;
1005
1006 if (dirp == NULL)
1007 return NULL;
1008
1009 if (dirp->find_handle == INVALID_HANDLE_VALUE) {
1010 char search_pattern[MAX_PATH];
1011
1012 snprintf(search_pattern, sizeof(search_pattern), "%s\\*",
1013 dirp->dirname);
1014 dirp->find_handle = FindFirstFileA(search_pattern, &find_data);
1015 if (dirp->find_handle == INVALID_HANDLE_VALUE)
1016 return NULL;
1017 } else {
1018 if (!FindNextFile(dirp->find_handle, &find_data))
1019 return NULL;
1020 }
1021
1022 snprintf(de.d_name, sizeof(de.d_name), find_data.cFileName);
1023 de.d_ino = 0;
1024
1025 return &de;
1026}
1027
1028uid_t geteuid(void)
1029{
1030 log_err("%s is not implemented\n", __func__);
1031 errno = ENOSYS;
1032 return -1;
1033}
1034
1035in_addr_t inet_network(const char *cp)
1036{
1037 in_addr_t hbo;
1038 in_addr_t nbo = inet_addr(cp);
1039 hbo = ((nbo & 0xFF) << 24) + ((nbo & 0xFF00) << 8) + ((nbo & 0xFF0000) >> 8) + ((nbo & 0xFF000000) >> 24);
1040 return hbo;
1041}
1042
1043static HANDLE create_named_pipe(char *pipe_name, int wait_connect_time)
1044{
1045 HANDLE hpipe;
1046
1047 hpipe = CreateNamedPipe (
1048 pipe_name,
1049 PIPE_ACCESS_DUPLEX,
1050 PIPE_WAIT | PIPE_TYPE_BYTE,
1051 1, 0, 0, wait_connect_time, NULL);
1052
1053 if (hpipe == INVALID_HANDLE_VALUE) {
1054 log_err("ConnectNamedPipe failed (%lu).\n", GetLastError());
1055 return INVALID_HANDLE_VALUE;
1056 }
1057
1058 if (!ConnectNamedPipe(hpipe, NULL)) {
1059 log_err("ConnectNamedPipe failed (%lu).\n", GetLastError());
1060 CloseHandle(hpipe);
1061 return INVALID_HANDLE_VALUE;
1062 }
1063
1064 return hpipe;
1065}
1066
1067static BOOL windows_create_process(PROCESS_INFORMATION *pi, const char *args, HANDLE *hjob)
1068{
1069 LPSTR this_cmd_line = GetCommandLine();
1070 LPSTR new_process_cmd_line = malloc((strlen(this_cmd_line)+strlen(args)) * sizeof(char *));
1071 STARTUPINFO si = {0};
1072 DWORD flags = 0;
1073
1074 strcpy(new_process_cmd_line, this_cmd_line);
1075 strcat(new_process_cmd_line, args);
1076
1077 si.cb = sizeof(si);
1078 memset(pi, 0, sizeof(*pi));
1079
1080 if ((hjob != NULL) && (*hjob != INVALID_HANDLE_VALUE))
1081 flags = CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB;
1082
1083 flags |= CREATE_NEW_CONSOLE;
1084
1085 if( !CreateProcess( NULL,
1086 new_process_cmd_line,
1087 NULL, /* Process handle not inherited */
1088 NULL, /* Thread handle not inherited */
1089 TRUE, /* no handle inheritance */
1090 flags,
1091 NULL, /* Use parent's environment block */
1092 NULL, /* Use parent's starting directory */
1093 &si,
1094 pi )
1095 )
1096 {
1097 log_err("CreateProcess failed (%lu).\n", GetLastError() );
1098 free(new_process_cmd_line);
1099 return 1;
1100 }
1101 if ((hjob != NULL) && (*hjob != INVALID_HANDLE_VALUE)) {
1102 BOOL ret = AssignProcessToJobObject(*hjob, pi->hProcess);
1103 if (!ret) {
1104 log_err("AssignProcessToJobObject failed (%lu).\n", GetLastError() );
1105 return 1;
1106 }
1107
1108 ResumeThread(pi->hThread);
1109 }
1110
1111 free(new_process_cmd_line);
1112 return 0;
1113}
1114
1115HANDLE windows_create_job(void)
1116{
1117 JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
1118 BOOL success;
1119 HANDLE hjob = CreateJobObject(NULL, NULL);
1120
1121 jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
1122 success = SetInformationJobObject(hjob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli));
1123 if ( success == 0 ) {
1124 log_err( "SetInformationJobObject failed: error %lu\n", GetLastError() );
1125 return INVALID_HANDLE_VALUE;
1126 }
1127 return hjob;
1128}
1129
1130/* wait for a child process to either exit or connect to a child */
1131static bool monitor_process_till_connect(PROCESS_INFORMATION *pi, HANDLE *hpipe)
1132{
1133 bool connected = FALSE;
1134 bool process_alive = TRUE;
1135 char buffer[32] = {0};
1136 DWORD bytes_read;
1137
1138 do {
1139 DWORD exit_code;
1140 GetExitCodeProcess(pi->hProcess, &exit_code);
1141 if (exit_code != STILL_ACTIVE) {
1142 dprint(FD_PROCESS, "process %u exited %d\n", GetProcessId(pi->hProcess), exit_code);
1143 break;
1144 }
1145
1146 memset(buffer, 0, sizeof(buffer));
1147 ReadFile(*hpipe, &buffer, sizeof(buffer) - 1, &bytes_read, NULL);
1148 if (bytes_read && strstr(buffer, "connected")) {
1149 dprint(FD_PROCESS, "process %u connected to client\n", GetProcessId(pi->hProcess));
1150 connected = TRUE;
1151 }
1152 usleep(10*1000);
1153 } while (process_alive && !connected);
1154 return connected;
1155}
1156
1157/*create a process with --server-internal to emulate fork() */
1158HANDLE windows_handle_connection(HANDLE hjob, int sk)
1159{
1160 char pipe_name[64] = "\\\\.\\pipe\\fiointernal-";
1161 char args[128] = " --server-internal=";
1162 PROCESS_INFORMATION pi;
1163 HANDLE hpipe = INVALID_HANDLE_VALUE;
1164 WSAPROTOCOL_INFO protocol_info;
1165 HANDLE ret;
1166
1167 sprintf(pipe_name+strlen(pipe_name), "%d", GetCurrentProcessId());
1168 sprintf(args+strlen(args), "%s", pipe_name);
1169
1170 if (windows_create_process(&pi, args, &hjob) != 0)
1171 return INVALID_HANDLE_VALUE;
1172 else
1173 ret = pi.hProcess;
1174
1175 /* duplicate socket and write the protocol_info to pipe so child can
1176 * duplicate the communication socket */
1177 if (WSADuplicateSocket(sk, GetProcessId(pi.hProcess), &protocol_info)) {
1178 log_err("WSADuplicateSocket failed (%lu).\n", GetLastError());
1179 ret = INVALID_HANDLE_VALUE;
1180 goto cleanup;
1181 }
1182
1183 /* make a pipe with a unique name based upon processid */
1184 hpipe = create_named_pipe(pipe_name, 1000);
1185 if (hpipe == INVALID_HANDLE_VALUE) {
1186 ret = INVALID_HANDLE_VALUE;
1187 goto cleanup;
1188 }
1189
1190 if (!WriteFile(hpipe, &protocol_info, sizeof(protocol_info), NULL, NULL)) {
1191 log_err("WriteFile failed (%lu).\n", GetLastError());
1192 ret = INVALID_HANDLE_VALUE;
1193 goto cleanup;
1194 }
1195
1196 dprint(FD_PROCESS, "process %d created child process %u\n", GetCurrentProcessId(), GetProcessId(pi.hProcess));
1197
1198 /* monitor the process until it either exits or connects. This level
1199 * doesnt care which of those occurs because the result is that it
1200 * needs to loop around and create another child process to monitor */
1201 if (!monitor_process_till_connect(&pi, &hpipe))
1202 ret = INVALID_HANDLE_VALUE;
1203
1204cleanup:
1205 /* close the handles and pipes because this thread is done monitoring them */
1206 if (ret == INVALID_HANDLE_VALUE)
1207 CloseHandle(pi.hProcess);
1208 CloseHandle(pi.hThread);
1209 DisconnectNamedPipe(hpipe);
1210 CloseHandle(hpipe);
1211 return ret;
1212}