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
28 extern unsigned long mtime_since_now(struct timespec *);
29 extern void fio_gettime(struct timespec *, void *);
30
win_to_posix_error(DWORD winerr)31 int 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
GetNumLogicalProcessors(void)178 int 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
sysconf(int name)211 long 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
247 char *dl_error = NULL;
248
dlclose(void * handle)249 int dlclose(void *handle)
250 {
251 return !FreeLibrary((HMODULE)handle);
252 }
253
dlopen(const char * file,int mode)254 void *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
dlsym(void * handle,const char * name)267 void *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
dlerror(void)280 char *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 */
Time_tToSystemTime(time_t dosTime,SYSTEMTIME * systemTime)286 void 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
ctime_r(const time_t * t,char * buf)300 char *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
gettimeofday(struct timeval * restrict tp,void * restrict tzp)320 int 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
sigaction(int sig,const struct sigaction * act,struct sigaction * oact)344 int 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
lstat(const char * path,struct stat * buf)359 int lstat(const char *path, struct stat *buf)
360 {
361 return stat(path, buf);
362 }
363
mmap(void * addr,size_t len,int prot,int flags,int fildes,off_t off)364 void *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
munmap(void * addr,size_t len)412 int 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
msync(void * addr,size_t len,int flags)427 int msync(void *addr, size_t len, int flags)
428 {
429 return !FlushViewOfFile(addr, len);
430 }
431
fork(void)432 int fork(void)
433 {
434 log_err("%s is not implemented\n", __func__);
435 errno = ENOSYS;
436 return -1;
437 }
438
setsid(void)439 pid_t setsid(void)
440 {
441 log_err("%s is not implemented\n", __func__);
442 errno = ENOSYS;
443 return -1;
444 }
445
446 static HANDLE log_file = INVALID_HANDLE_VALUE;
447
openlog(const char * ident,int logopt,int facility)448 void 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
closelog(void)458 void closelog(void)
459 {
460 CloseHandle(log_file);
461 log_file = INVALID_HANDLE_VALUE;
462 }
463
syslog(int priority,const char * message,...)464 void 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
kill(pid_t pid,int sig)491 int 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 */
fcntl(int fildes,int cmd,...)501 int 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
537 return 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 */
clock_gettime(clockid_t clock_id,struct timespec * tp)545 int 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
mlock(const void * addr,size_t len)583 int 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
munlock(const void * addr,size_t len)612 int 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
waitpid(pid_t pid,int * stat_loc,int options)624 pid_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
usleep(useconds_t useconds)631 int usleep(useconds_t useconds)
632 {
633 Sleep(useconds / 1000);
634 return 0;
635 }
636
basename(char * path)637 char *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
fsync(int fildes)656 int 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
667 int nFileMappings = 0;
668 HANDLE fileMappings[1024];
669
shmget(key_t key,size_t size,int shmflg)670 int 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
shmat(int shmid,const void * shmaddr,int shmflg)690 void *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
shmdt(const void * shmaddr)715 int 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
shmctl(int shmid,int cmd,struct shmid_ds * buf)725 int 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
setuid(uid_t uid)737 int setuid(uid_t uid)
738 {
739 log_err("%s is not implemented\n", __func__);
740 errno = ENOSYS;
741 return -1;
742 }
743
setgid(gid_t gid)744 int setgid(gid_t gid)
745 {
746 log_err("%s is not implemented\n", __func__);
747 errno = ENOSYS;
748 return -1;
749 }
750
nice(int incr)751 int 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
getrusage(int who,struct rusage * r_usage)770 int 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
posix_madvise(void * addr,size_t len,int advice)806 int posix_madvise(void *addr, size_t len, int advice)
807 {
808 return ENOSYS;
809 }
810
fdatasync(int fildes)811 int fdatasync(int fildes)
812 {
813 return fsync(fildes);
814 }
815
pwrite(int fildes,const void * buf,size_t nbyte,off_t offset)816 ssize_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
pread(int fildes,void * buf,size_t nbyte,off_t offset)826 ssize_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
readv(int fildes,const struct iovec * iov,int iovcnt)835 ssize_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
writev(int fildes,const struct iovec * iov,int iovcnt)842 ssize_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
strtoll(const char * restrict str,char ** restrict endptr,int base)863 long long strtoll(const char *restrict str, char **restrict endptr, int base)
864 {
865 return _strtoi64(str, endptr, base);
866 }
867
poll(struct pollfd fds[],nfds_t nfds,int timeout)868 int 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
nanosleep(const struct timespec * rqtp,struct timespec * rmtp)920 int 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
opendir(const char * dirname)948 DIR *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
closedir(DIR * dirp)979 int 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
readdir(DIR * dirp)988 struct 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
geteuid(void)1015 uid_t geteuid(void)
1016 {
1017 log_err("%s is not implemented\n", __func__);
1018 errno = ENOSYS;
1019 return -1;
1020 }
1021
inet_network(const char * cp)1022 in_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 }
1029