posix.c revision e5b8f91cc6229a5f8b38f1338fad29c800fef179
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 <stdlib.h> 11#include <unistd.h> 12#include <dirent.h> 13#include <pthread.h> 14#include <semaphore.h> 15#include <sys/shm.h> 16#include <sys/mman.h> 17#include <sys/uio.h> 18#include <sys/resource.h> 19#include <sys/poll.h> 20 21#include "../os-windows.h" 22 23long sysconf(int name) 24{ 25 long long val = -1; 26 DWORD len; 27 SYSTEM_LOGICAL_PROCESSOR_INFORMATION processorInfo; 28 SYSTEM_INFO sysInfo; 29 MEMORYSTATUSEX status; 30 31 switch (name) 32 { 33 case _SC_NPROCESSORS_ONLN: 34 len = sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); 35 GetLogicalProcessorInformation(&processorInfo, &len); 36 val = len / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION); 37 break; 38 39 case _SC_PAGESIZE: 40 GetSystemInfo(&sysInfo); 41 val = sysInfo.dwPageSize; 42 break; 43 44 case _SC_PHYS_PAGES: 45 status.dwLength = sizeof(status); 46 GlobalMemoryStatusEx(&status); 47 val = status.ullTotalPhys; 48 break; 49 default: 50 log_err("sysconf(%d) is not implemented\n", name); 51 break; 52 } 53 54 return val; 55} 56 57char *dl_error = NULL; 58 59int dlclose(void *handle) 60{ 61 return !FreeLibrary((HMODULE)handle); 62} 63 64void *dlopen(const char *file, int mode) 65{ 66 HMODULE hMod; 67 68 hMod = LoadLibrary(file); 69 if (hMod == INVALID_HANDLE_VALUE) 70 dl_error = (char*)"LoadLibrary failed"; 71 else 72 dl_error = NULL; 73 74 return hMod; 75} 76 77void *dlsym(void *handle, const char *name) 78{ 79 FARPROC fnPtr; 80 81 fnPtr = GetProcAddress((HMODULE)handle, name); 82 if (fnPtr == NULL) 83 dl_error = (char*)"GetProcAddress failed"; 84 else 85 dl_error = NULL; 86 87 return fnPtr; 88} 89 90char *dlerror(void) 91{ 92 return dl_error; 93} 94 95int gettimeofday(struct timeval *restrict tp, void *restrict tzp) 96{ 97 FILETIME fileTime; 98 unsigned long long unix_time, windows_time; 99 const time_t MILLISECONDS_BETWEEN_1601_AND_1970 = 11644473600000; 100 101 /* Ignore the timezone parameter */ 102 (void)tzp; 103 104 /* 105 * Windows time is stored as the number 100 ns intervals since January 1 1601. 106 * Conversion details from http://www.informit.com/articles/article.aspx?p=102236&seqNum=3 107 * Its precision is 100 ns but accuracy is only one clock tick, or normally around 15 ms. 108 */ 109 GetSystemTimeAsFileTime(&fileTime); 110 windows_time = ((unsigned long long)fileTime.dwHighDateTime << 32) + fileTime.dwLowDateTime; 111 /* Divide by 10,000 to convert to ms and subtract the time between 1601 and 1970 */ 112 unix_time = (((windows_time)/10000) - MILLISECONDS_BETWEEN_1601_AND_1970); 113 /* unix_time is now the number of milliseconds since 1970 (the Unix epoch) */ 114 tp->tv_sec = unix_time / 1000; 115 tp->tv_usec = (unix_time % 1000) * 1000; 116 return 0; 117} 118 119void syslog(int priority, const char *message, ... /* argument */) 120{ 121 log_err("%s is not implemented\n", __func__); 122} 123 124int sigaction(int sig, const struct sigaction *act, 125 struct sigaction *oact) 126{ 127 int rc = 0; 128 void (*prev_handler)(int); 129 130 prev_handler = signal(sig, act->sa_handler); 131 if (oact != NULL) 132 oact->sa_handler = prev_handler; 133 134 if (prev_handler == SIG_ERR) 135 rc = -1; 136 137 return rc; 138} 139 140int lstat(const char * path, struct stat * buf) 141{ 142 return stat(path, buf); 143} 144 145void *mmap(void *addr, size_t len, int prot, int flags, 146 int fildes, off_t off) 147{ 148 DWORD vaProt = 0; 149 void* allocAddr = NULL; 150 151 if (prot & PROT_NONE) 152 vaProt |= PAGE_NOACCESS; 153 154 if ((prot & PROT_READ) && !(prot & PROT_WRITE)) 155 vaProt |= PAGE_READONLY; 156 157 if (prot & PROT_WRITE) 158 vaProt |= PAGE_READWRITE; 159 160 if ((flags & MAP_ANON) | (flags & MAP_ANONYMOUS)) 161 { 162 allocAddr = VirtualAlloc(addr, len, MEM_COMMIT, vaProt); 163 } 164 165 return allocAddr; 166} 167 168int munmap(void *addr, size_t len) 169{ 170 return !VirtualFree(addr, 0, MEM_RELEASE); 171} 172 173int fork(void) 174{ 175 log_err("%s is not implemented\n", __func__); 176 errno = ENOSYS; 177 return (-1); 178} 179 180pid_t setsid(void) 181{ 182 log_err("%s is not implemented\n", __func__); 183 errno = ENOSYS; 184 return (-1); 185} 186 187void openlog(const char *ident, int logopt, int facility) 188{ 189 log_err("%s is not implemented\n", __func__); 190} 191 192void closelog(void) 193{ 194 log_err("%s is not implemented\n", __func__); 195} 196 197int kill(pid_t pid, int sig) 198{ 199 errno = ESRCH; 200 return (-1); 201} 202 203/* 204 * This is assumed to be used only by the network code, 205 * and so doesn't try and handle any of the other cases 206 */ 207int fcntl(int fildes, int cmd, ...) 208{ 209 /* 210 * non-blocking mode doesn't work the same as in BSD sockets, 211 * so ignore it. 212 */ 213#if 0 214 va_list ap; 215 int val, opt, status; 216 217 if (cmd == F_GETFL) 218 return 0; 219 else if (cmd != F_SETFL) { 220 errno = EINVAL; 221 return (-1); 222 } 223 224 va_start(ap, 1); 225 226 opt = va_arg(ap, int); 227 if (opt & O_NONBLOCK) 228 val = 1; 229 else 230 val = 0; 231 232 status = ioctlsocket((SOCKET)fildes, opt, &val); 233 234 if (status == SOCKET_ERROR) { 235 errno = EINVAL; 236 val = -1; 237 } 238 239 va_end(ap); 240 241 return val; 242#endif 243return 0; 244} 245 246/* 247 * Get the value of a local clock source. 248 * This implementation supports 2 clocks: CLOCK_MONOTONIC provides high-accuracy 249 * relative time, while CLOCK_REALTIME provides a low-accuracy wall time. 250 */ 251int clock_gettime(clockid_t clock_id, struct timespec *tp) 252{ 253 int rc = 0; 254 255 if (clock_id == CLOCK_MONOTONIC) 256 { 257 static LARGE_INTEGER freq = {{0,0}}; 258 LARGE_INTEGER counts; 259 260 QueryPerformanceCounter(&counts); 261 if (freq.QuadPart == 0) 262 QueryPerformanceFrequency(&freq); 263 264 tp->tv_sec = counts.QuadPart / freq.QuadPart; 265 /* Get the difference between the number of ns stored 266 * in 'tv_sec' and that stored in 'counts' */ 267 unsigned long long t = tp->tv_sec * freq.QuadPart; 268 t = counts.QuadPart - t; 269 /* 't' now contains the number of cycles since the last second. 270 * We want the number of nanoseconds, so multiply out by 1,000,000,000 271 * and then divide by the frequency. */ 272 t *= 1000000000; 273 tp->tv_nsec = t / freq.QuadPart; 274 } 275 else if (clock_id == CLOCK_REALTIME) 276 { 277 /* clock_gettime(CLOCK_REALTIME,...) is just an alias for gettimeofday with a 278 * higher-precision field. */ 279 struct timeval tv; 280 gettimeofday(&tv, NULL); 281 tp->tv_sec = tv.tv_sec; 282 tp->tv_nsec = tv.tv_usec * 1000; 283 } else { 284 errno = EINVAL; 285 rc = -1; 286 } 287 288 return rc; 289} 290 291int mlock(const void * addr, size_t len) 292{ 293 return !VirtualLock((LPVOID)addr, len); 294} 295 296int munlock(const void * addr, size_t len) 297{ 298 return !VirtualUnlock((LPVOID)addr, len); 299} 300 301pid_t waitpid(pid_t pid, int *stat_loc, int options) 302{ 303 log_err("%s is not implemented\n", __func__); 304 errno = ENOSYS; 305 return -1; 306} 307 308int usleep(useconds_t useconds) 309{ 310 Sleep(useconds / 1000); 311 return 0; 312} 313 314char *basename(char *path) 315{ 316 static char name[MAX_PATH]; 317 int i; 318 319 if (path == NULL || strlen(path) == 0) 320 return (char*)"."; 321 322 i = strlen(path) - 1; 323 324 while (name[i] != '\\' && name[i] != '/' && i >= 0) 325 i--; 326 327 strcpy(name, path + i); 328 329 return name; 330} 331 332int posix_fallocate(int fd, off_t offset, off_t len) 333{ 334 log_err("%s is not implemented\n", __func__); 335 errno = ENOSYS; 336 return (-1); 337} 338 339int ftruncate(int fildes, off_t length) 340{ 341 BOOL bSuccess; 342 int old_pos = tell(fildes); 343 lseek(fildes, length, SEEK_SET); 344 HANDLE hFile = (HANDLE)_get_osfhandle(fildes); 345 bSuccess = SetEndOfFile(hFile); 346 lseek(fildes, old_pos, SEEK_SET); 347 return !bSuccess; 348} 349 350int fsync(int fildes) 351{ 352 HANDLE hFile = (HANDLE)_get_osfhandle(fildes); 353 return !FlushFileBuffers(hFile); 354} 355 356int nFileMappings = 0; 357HANDLE fileMappings[1024]; 358 359int shmget(key_t key, size_t size, int shmflg) 360{ 361 int mapid = -1; 362 HANDLE hMapping = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, (PAGE_EXECUTE_READWRITE | SEC_RESERVE), size >> 32, size & 0xFFFFFFFF, NULL); 363 if (hMapping != NULL) { 364 fileMappings[nFileMappings] = hMapping; 365 mapid = nFileMappings; 366 nFileMappings++; 367 } else { 368 errno = ENOSYS; 369 } 370 371 return mapid; 372} 373 374void *shmat(int shmid, const void *shmaddr, int shmflg) 375{ 376 void* mapAddr; 377 MEMORY_BASIC_INFORMATION memInfo; 378 mapAddr = MapViewOfFile(fileMappings[shmid], FILE_MAP_ALL_ACCESS, 0, 0, 0); 379 VirtualQuery(mapAddr, &memInfo, sizeof(memInfo)); 380 mapAddr = VirtualAlloc(mapAddr, memInfo.RegionSize, MEM_COMMIT, PAGE_READWRITE); 381 return mapAddr; 382} 383 384int shmdt(const void *shmaddr) 385{ 386 return !UnmapViewOfFile(shmaddr); 387} 388 389int shmctl(int shmid, int cmd, struct shmid_ds *buf) 390{ 391 if (cmd == IPC_RMID) { 392 fileMappings[shmid] = INVALID_HANDLE_VALUE; 393 return 0; 394 } else { 395 log_err("%s is not implemented\n", __func__); 396 } 397 return (-1); 398} 399 400int setuid(uid_t uid) 401{ 402 log_err("%s is not implemented\n", __func__); 403 errno = ENOSYS; 404 return (-1); 405} 406 407int setgid(gid_t gid) 408{ 409 log_err("%s is not implemented\n", __func__); 410 errno = ENOSYS; 411 return (-1); 412} 413 414int nice(int incr) 415{ 416 if (incr != 0) { 417 errno = EINVAL; 418 return -1; 419 } 420 421 return 0; 422} 423 424int getrusage(int who, struct rusage *r_usage) 425{ 426 const time_t SECONDS_BETWEEN_1601_AND_1970 = 11644473600; 427 FILETIME cTime, eTime, kTime, uTime; 428 time_t time; 429 430 memset(r_usage, 0, sizeof(*r_usage)); 431 432 HANDLE hProcess = GetCurrentProcess(); 433 GetProcessTimes(hProcess, &cTime, &eTime, &kTime, &uTime); 434 time = ((unsigned long long)uTime.dwHighDateTime << 32) + uTime.dwLowDateTime; 435 /* Divide by 10,000,000 to get the number of seconds and move the epoch from 436 * 1601 to 1970 */ 437 time = (time_t)(((time)/10000000) - SECONDS_BETWEEN_1601_AND_1970); 438 r_usage->ru_utime.tv_sec = time; 439 /* getrusage() doesn't care about anything other than seconds, so set tv_usec to 0 */ 440 r_usage->ru_utime.tv_usec = 0; 441 time = ((unsigned long long)kTime.dwHighDateTime << 32) + kTime.dwLowDateTime; 442 /* Divide by 10,000,000 to get the number of seconds and move the epoch from 443 * 1601 to 1970 */ 444 time = (time_t)(((time)/10000000) - SECONDS_BETWEEN_1601_AND_1970); 445 r_usage->ru_stime.tv_sec = time; 446 r_usage->ru_stime.tv_usec = 0; 447 return 0; 448} 449 450int posix_madvise(void *addr, size_t len, int advice) 451{ 452 log_err("%s is not implemented\n", __func__); 453 return ENOSYS; 454} 455 456/* Windows doesn't support advice for memory pages. Just ignore it. */ 457int msync(void *addr, size_t len, int flags) 458{ 459 log_err("%s is not implemented\n", __func__); 460 errno = ENOSYS; 461 return -1; 462} 463 464int fdatasync(int fildes) 465{ 466 return fsync(fildes); 467} 468 469ssize_t pwrite(int fildes, const void *buf, size_t nbyte, 470 off_t offset) 471{ 472 long pos = tell(fildes); 473 ssize_t len = write(fildes, buf, nbyte); 474 lseek(fildes, pos, SEEK_SET); 475 return len; 476} 477 478ssize_t pread(int fildes, void *buf, size_t nbyte, off_t offset) 479{ 480 long pos = tell(fildes); 481 ssize_t len = read(fildes, buf, nbyte); 482 lseek(fildes, pos, SEEK_SET); 483 return len; 484} 485 486ssize_t readv(int fildes, const struct iovec *iov, int iovcnt) 487{ 488 log_err("%s is not implemented\n", __func__); 489 errno = ENOSYS; 490 return (-1); 491} 492 493ssize_t writev(int fildes, const struct iovec *iov, int iovcnt) 494{ 495 log_err("%s is not implemented\n", __func__); 496 errno = ENOSYS; 497 return (-1); 498} 499 500long long strtoll(const char *restrict str, char **restrict endptr, 501 int base) 502{ 503 return _strtoi64(str, endptr, base); 504} 505 506char *strsep(char **stringp, const char *delim) 507{ 508 char *orig = *stringp; 509 BOOL gotMatch = FALSE; 510 int i = 0; 511 int j = 0; 512 513 if (*stringp == NULL) 514 return NULL; 515 516 while ((*stringp)[i] != '\0') { 517 j = 0; 518 while (delim[j] != '\0') { 519 if ((*stringp)[i] == delim[j]) { 520 gotMatch = TRUE; 521 (*stringp)[i] = '\0'; 522 *stringp = *stringp + i + 1; 523 break; 524 } 525 j++; 526 } 527 if (gotMatch) 528 break; 529 530 i++; 531 } 532 533 if (!gotMatch) 534 *stringp = NULL; 535 536 return orig; 537} 538 539int poll(struct pollfd fds[], nfds_t nfds, int timeout) 540{ 541 struct timeval tv; 542 struct timeval *to = NULL; 543 fd_set readfds, writefds, exceptfds; 544 int i; 545 int rc; 546 547 if (timeout != -1) 548 to = &tv; 549 550 to->tv_sec = timeout / 1000; 551 to->tv_usec = (timeout % 1000) * 1000; 552 553 FD_ZERO(&readfds); 554 FD_ZERO(&writefds); 555 FD_ZERO(&exceptfds); 556 557 for (i = 0; i < nfds; i++) 558 { 559 if (fds[i].fd < 0) { 560 fds[i].revents = 0; 561 continue; 562 } 563 564 if (fds[i].events & POLLIN) 565 FD_SET(fds[i].fd, &readfds); 566 567 if (fds[i].events & POLLOUT) 568 FD_SET(fds[i].fd, &writefds); 569 570 FD_SET(fds[i].fd, &exceptfds); 571 } 572 573 rc = select(nfds, &readfds, &writefds, &exceptfds, to); 574 575 if (rc != SOCKET_ERROR) { 576 for (i = 0; i < nfds; i++) 577 { 578 if (fds[i].fd < 0) { 579 continue; 580 } 581 582 if ((fds[i].events & POLLIN) && FD_ISSET(fds[i].fd, &readfds)) 583 fds[i].revents |= POLLIN; 584 585 if ((fds[i].events & POLLOUT) && FD_ISSET(fds[i].fd, &writefds)) 586 fds[i].revents |= POLLOUT; 587 588 if (FD_ISSET(fds[i].fd, &exceptfds)) 589 fds[i].revents |= POLLHUP; 590 } 591 } 592 593 return rc; 594} 595 596int nanosleep(const struct timespec *rqtp, struct timespec *rmtp) 597{ 598 log_err("%s is not implemented\n", __func__); 599 errno = ENOSYS; 600 return -1; 601} 602 603DIR *opendir(const char *dirname) 604{ 605 log_err("%s is not implemented\n", __func__); 606 errno = ENOSYS; 607 return NULL; 608} 609 610int closedir(DIR *dirp) 611{ 612 log_err("%s is not implemented\n", __func__); 613 errno = ENOSYS; 614 return -1; 615} 616 617struct dirent *readdir(DIR *dirp) 618{ 619 log_err("%s is not implemented\n", __func__); 620 errno = ENOSYS; 621 return NULL; 622} 623 624uid_t geteuid(void) 625{ 626 log_err("%s is not implemented\n", __func__); 627 errno = ENOSYS; 628 return -1; 629} 630 631int inet_aton(char *addr) 632{ 633 log_err("%s is not implemented\n", __func__); 634 errno = ENOSYS; 635 return 0; 636} 637 638const char* inet_ntop(int af, const void *restrict src, 639 char *restrict dst, socklen_t size) 640{ 641 INT status = SOCKET_ERROR; 642 WSADATA wsd; 643 char *ret = NULL; 644 645 if (af != AF_INET && af != AF_INET6) { 646 errno = EAFNOSUPPORT; 647 return NULL; 648 } 649 650 WSAStartup(MAKEWORD(2,2), &wsd); 651 652 if (af == AF_INET) { 653 struct sockaddr_in si; 654 DWORD len = size; 655 memset(&si, 0, sizeof(si)); 656 si.sin_family = af; 657 memcpy(&si.sin_addr, src, sizeof(si.sin_addr)); 658 status = WSAAddressToString((struct sockaddr*)&si, sizeof(si), NULL, dst, &len); 659 } else if (af == AF_INET6) { 660 struct sockaddr_in6 si6; 661 DWORD len = size; 662 memset(&si6, 0, sizeof(si6)); 663 si6.sin6_family = af; 664 memcpy(&si6.sin6_addr, src, sizeof(si6.sin6_addr)); 665 status = WSAAddressToString((struct sockaddr*)&si6, sizeof(si6), NULL, dst, &len); 666 } 667 668 if (status != SOCKET_ERROR) 669 ret = dst; 670 else 671 errno = ENOSPC; 672 673 WSACleanup(); 674 return ret; 675} 676 677int inet_pton(int af, const char *restrict src, void *restrict dst) 678{ 679 INT status = SOCKET_ERROR; 680 WSADATA wsd; 681 int ret = 1; 682 683 if (af != AF_INET && af != AF_INET6) { 684 errno = EAFNOSUPPORT; 685 return -1; 686 } 687 688 WSAStartup(MAKEWORD(2,2), &wsd); 689 690 if (af == AF_INET) { 691 struct sockaddr_in si; 692 INT len = sizeof(si); 693 memset(&si, 0, sizeof(si)); 694 si.sin_family = af; 695 status = WSAStringToAddressA((char*)src, af, NULL, (struct sockaddr*)&si, &len); 696 if (status != SOCKET_ERROR) 697 memcpy(dst, &si.sin_addr, sizeof(si.sin_addr)); 698 } else if (af == AF_INET6) { 699 struct sockaddr_in6 si6; 700 INT len = sizeof(si6); 701 memset(&si6, 0, sizeof(si6)); 702 si6.sin6_family = af; 703 status = WSAStringToAddressA((char*)src, af, NULL, (struct sockaddr*)&si6, &len); 704 if (status != SOCKET_ERROR) 705 memcpy(dst, &si6.sin6_addr, sizeof(si6.sin6_addr)); 706 } 707 708 if (status == SOCKET_ERROR) { 709 errno = ENOSPC; 710 ret = 0; 711 } 712 713 WSACleanup(); 714 715 return ret; 716} 717