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.
7 #include <netinet/in.h>
16 #include <semaphore.h>
20 #include <sys/resource.h>
25 #include "../os-windows.h"
26 #include "../../lib/hweight.h"
28 extern unsigned long mtime_since_now(struct timespec *);
29 extern void fio_gettime(struct timespec *, void *);
31 int win_to_posix_error(DWORD winerr)
36 case ERROR_FILE_NOT_FOUND:
38 case ERROR_PATH_NOT_FOUND:
40 case ERROR_ACCESS_DENIED:
42 case ERROR_INVALID_HANDLE:
44 case ERROR_NOT_ENOUGH_MEMORY:
46 case ERROR_INVALID_DATA:
48 case ERROR_OUTOFMEMORY:
50 case ERROR_INVALID_DRIVE:
52 case ERROR_NOT_SAME_DEVICE:
54 case ERROR_WRITE_PROTECT:
60 case ERROR_SHARING_VIOLATION:
62 case ERROR_LOCK_VIOLATION:
64 case ERROR_SHARING_BUFFER_EXCEEDED:
66 case ERROR_HANDLE_DISK_FULL:
68 case ERROR_NOT_SUPPORTED:
70 case ERROR_FILE_EXISTS:
72 case ERROR_CANNOT_MAKE:
74 case ERROR_INVALID_PARAMETER:
76 case ERROR_NO_PROC_SLOTS:
78 case ERROR_BROKEN_PIPE:
80 case ERROR_OPEN_FAILED:
82 case ERROR_NO_MORE_SEARCH_HANDLES:
84 case ERROR_CALL_NOT_IMPLEMENTED:
86 case ERROR_INVALID_NAME:
88 case ERROR_WAIT_NO_CHILDREN:
90 case ERROR_CHILD_NOT_COMPLETE:
92 case ERROR_DIR_NOT_EMPTY:
94 case ERROR_SIGNAL_REFUSED:
96 case ERROR_BAD_PATHNAME:
98 case ERROR_SIGNAL_PENDING:
100 case ERROR_MAX_THRDS_REACHED:
104 case ERROR_ALREADY_EXISTS:
106 case ERROR_NO_SIGNAL_SENT:
108 case ERROR_FILENAME_EXCED_RANGE:
110 case ERROR_META_EXPANSION_TOO_LONG:
112 case ERROR_INVALID_SIGNAL_NUMBER:
114 case ERROR_THREAD_1_INACTIVE:
118 case ERROR_PIPE_BUSY:
122 case ERROR_MORE_DATA:
124 case ERROR_DIRECTORY:
126 case ERROR_PIPE_CONNECTED:
130 case ERROR_PROCESS_ABORTED:
132 case ERROR_BAD_DEVICE:
134 case ERROR_BAD_USERNAME:
136 case ERROR_OPEN_FILES:
138 case ERROR_ACTIVE_CONNECTIONS:
140 case ERROR_DEVICE_IN_USE:
142 case ERROR_INVALID_AT_INTERRUPT_TIME:
144 case ERROR_IO_DEVICE:
146 case ERROR_NOT_OWNER:
148 case ERROR_END_OF_MEDIA:
150 case ERROR_EOM_OVERFLOW:
152 case ERROR_BEGINNING_OF_MEDIA:
154 case ERROR_SETMARK_DETECTED:
156 case ERROR_NO_DATA_DETECTED:
158 case ERROR_POSSIBLE_DEADLOCK:
162 case ERROR_NEGATIVE_SEEK:
164 case ERROR_DISK_FULL:
168 case ERROR_FILE_INVALID:
171 log_err("fio: windows error %lu not handled\n", winerr);
178 int GetNumLogicalProcessors(void)
180 SYSTEM_LOGICAL_PROCESSOR_INFORMATION *processor_info = NULL;
182 DWORD num_processors = 0;
186 while (!GetLogicalProcessorInformation(processor_info, &len)) {
187 error = GetLastError();
188 if (error == ERROR_INSUFFICIENT_BUFFER)
189 processor_info = malloc(len);
191 log_err("Error: GetLogicalProcessorInformation failed: %lu\n",
196 if (processor_info == NULL) {
197 log_err("Error: failed to allocate memory for GetLogicalProcessorInformation");
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);
207 free(processor_info);
208 return num_processors;
211 long sysconf(int name)
216 MEMORYSTATUSEX status;
219 case _SC_NPROCESSORS_ONLN:
220 val = GetNumLogicalProcessors();
222 log_err("sysconf(_SC_NPROCESSORS_ONLN) failed\n");
227 GetSystemInfo(&sysInfo);
228 val = sysInfo.dwPageSize;
232 status.dwLength = sizeof(status);
233 val2 = sysconf(_SC_PAGESIZE);
234 if (GlobalMemoryStatusEx(&status) && val2 != -1)
235 val = status.ullTotalPhys / val2;
237 log_err("sysconf(_SC_PHYS_PAGES) failed\n");
240 log_err("sysconf(%d) is not implemented\n", name);
247 char *dl_error = NULL;
249 int dlclose(void *handle)
251 return !FreeLibrary((HMODULE)handle);
254 void *dlopen(const char *file, int mode)
258 hMod = LoadLibrary(file);
259 if (hMod == INVALID_HANDLE_VALUE)
260 dl_error = (char*)"LoadLibrary failed";
267 void *dlsym(void *handle, const char *name)
271 fnPtr = GetProcAddress((HMODULE)handle, name);
273 dl_error = (char*)"GetProcAddress failed";
285 /* Copied from http://blogs.msdn.com/b/joshpoley/archive/2007/12/19/date-time-formats-and-conversions.aspx */
286 void Time_tToSystemTime(time_t dosTime, SYSTEMTIME *systemTime)
290 SYSTEMTIME tempSystemTime;
292 jan1970 = Int32x32To64(dosTime, 10000000) + 116444736000000000;
293 utcFT.dwLowDateTime = (DWORD)jan1970;
294 utcFT.dwHighDateTime = jan1970 >> 32;
296 FileTimeToSystemTime((FILETIME*)&utcFT, &tempSystemTime);
297 SystemTimeToTzSpecificLocalTime(NULL, &tempSystemTime, systemTime);
300 char *ctime_r(const time_t *t, char *buf)
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" };
306 Time_tToSystemTime(*t, &systime);
309 * We don't know how long `buf` is, but assume it's rounded up from
310 * the minimum of 25 to 32
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);
320 int gettimeofday(struct timeval *restrict tp, void *restrict tzp)
323 uint64_t unix_time, windows_time;
324 const uint64_t MILLISECONDS_BETWEEN_1601_AND_1970 = 11644473600000;
326 /* Ignore the timezone parameter */
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.
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;
344 int sigaction(int sig, const struct sigaction *act, struct sigaction *oact)
347 void (*prev_handler)(int);
349 prev_handler = signal(sig, act->sa_handler);
351 oact->sa_handler = prev_handler;
353 if (prev_handler == SIG_ERR)
359 int lstat(const char *path, struct stat *buf)
361 return stat(path, buf);
364 void *mmap(void *addr, size_t len, int prot, int flags, int fildes, off_t off)
371 void* allocAddr = NULL;
373 if (prot & PROT_NONE)
374 vaProt |= PAGE_NOACCESS;
376 if ((prot & PROT_READ) && !(prot & PROT_WRITE)) {
377 vaProt |= PAGE_READONLY;
378 mapAccess = FILE_MAP_READ;
381 if (prot & PROT_WRITE) {
382 vaProt |= PAGE_READWRITE;
383 mapAccess |= FILE_MAP_WRITE;
386 lenlow = len & 0xFFFF;
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. */
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());
398 hMap = CreateFileMapping((HANDLE)_get_osfhandle(fildes), NULL,
399 vaProt, lenhigh, lenlow, NULL);
402 allocAddr = MapViewOfFile(hMap, mapAccess, off >> 16,
404 if (hMap == NULL || allocAddr == NULL)
405 errno = win_to_posix_error(GetLastError());
412 int munmap(void *addr, size_t len)
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);
422 success = VirtualFree(addr, 0, MEM_RELEASE);
427 int msync(void *addr, size_t len, int flags)
429 return !FlushViewOfFile(addr, len);
434 log_err("%s is not implemented\n", __func__);
441 log_err("%s is not implemented\n", __func__);
446 static HANDLE log_file = INVALID_HANDLE_VALUE;
448 void openlog(const char *ident, int logopt, int facility)
450 if (log_file != INVALID_HANDLE_VALUE)
453 log_file = CreateFileA("syslog.txt", GENERIC_WRITE,
454 FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
455 OPEN_ALWAYS, 0, NULL);
460 CloseHandle(log_file);
461 log_file = INVALID_HANDLE_VALUE;
464 void syslog(int priority, const char *message, ... /* argument */)
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);
477 if (log_file == INVALID_HANDLE_VALUE) {
478 log_err("syslog: failed to open log file\n");
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);
491 int kill(pid_t pid, int sig)
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
501 int fcntl(int fildes, int cmd, ...)
504 * non-blocking mode doesn't work the same as in BSD sockets,
509 int val, opt, status;
513 else if (cmd != F_SETFL) {
520 opt = va_arg(ap, int);
521 if (opt & O_NONBLOCK)
526 status = ioctlsocket((SOCKET)fildes, opt, &val);
528 if (status == SOCKET_ERROR) {
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.
545 int clock_gettime(clockid_t clock_id, struct timespec *tp)
549 if (clock_id == CLOCK_MONOTONIC) {
550 static LARGE_INTEGER freq = {{0,0}};
551 LARGE_INTEGER counts;
554 QueryPerformanceCounter(&counts);
555 if (freq.QuadPart == 0)
556 QueryPerformanceFrequency(&freq);
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. */
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. */
572 gettimeofday(&tv, NULL);
573 tp->tv_sec = tv.tv_sec;
574 tp->tv_nsec = tv.tv_usec * 1000;
583 int mlock(const void * addr, size_t len)
587 HANDLE process = GetCurrentProcess();
589 success = GetProcessWorkingSetSize(process, &min, &max);
591 errno = win_to_posix_error(GetLastError());
597 success = SetProcessWorkingSetSize(process, min, max);
599 errno = win_to_posix_error(GetLastError());
603 success = VirtualLock((LPVOID)addr, len);
605 errno = win_to_posix_error(GetLastError());
612 int munlock(const void * addr, size_t len)
614 BOOL success = VirtualUnlock((LPVOID)addr, len);
617 errno = win_to_posix_error(GetLastError());
624 pid_t waitpid(pid_t pid, int *stat_loc, int options)
626 log_err("%s is not implemented\n", __func__);
631 int usleep(useconds_t useconds)
633 Sleep(useconds / 1000);
637 char *basename(char *path)
639 static char name[MAX_PATH];
642 if (path == NULL || strlen(path) == 0)
645 i = strlen(path) - 1;
647 while (path[i] != '\\' && path[i] != '/' && i >= 0)
650 name[MAX_PATH - 1] = '\0';
651 strncpy(name, path + i + 1, MAX_PATH - 1);
656 int fsync(int fildes)
658 HANDLE hFile = (HANDLE)_get_osfhandle(fildes);
659 if (!FlushFileBuffers(hFile)) {
660 errno = win_to_posix_error(GetLastError());
667 int nFileMappings = 0;
668 HANDLE fileMappings[1024];
670 int shmget(key_t key, size_t size, int shmflg)
673 uint32_t size_low = size & 0xFFFFFFFF;
674 uint32_t size_high = ((uint64_t)size) >> 32;
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;
690 void *shmat(int shmid, const void *shmaddr, int shmflg)
693 MEMORY_BASIC_INFORMATION memInfo;
695 mapAddr = MapViewOfFile(fileMappings[shmid], FILE_MAP_ALL_ACCESS, 0, 0, 0);
696 if (mapAddr == NULL) {
697 errno = win_to_posix_error(GetLastError());
701 if (VirtualQuery(mapAddr, &memInfo, sizeof(memInfo)) == 0) {
702 errno = win_to_posix_error(GetLastError());
706 mapAddr = VirtualAlloc(mapAddr, memInfo.RegionSize, MEM_COMMIT, PAGE_READWRITE);
707 if (mapAddr == NULL) {
708 errno = win_to_posix_error(GetLastError());
715 int shmdt(const void *shmaddr)
717 if (!UnmapViewOfFile(shmaddr)) {
718 errno = win_to_posix_error(GetLastError());
725 int shmctl(int shmid, int cmd, struct shmid_ds *buf)
727 if (cmd == IPC_RMID) {
728 fileMappings[shmid] = INVALID_HANDLE_VALUE;
732 log_err("%s is not implemented\n", __func__);
737 int setuid(uid_t uid)
739 log_err("%s is not implemented\n", __func__);
744 int setgid(gid_t gid)
746 log_err("%s is not implemented\n", __func__);
753 DWORD prioclass = NORMAL_PRIORITY_CLASS;
756 prioclass = HIGH_PRIORITY_CLASS;
758 prioclass = ABOVE_NORMAL_PRIORITY_CLASS;
760 prioclass = IDLE_PRIORITY_CLASS;
762 prioclass = BELOW_NORMAL_PRIORITY_CLASS;
764 if (!SetPriorityClass(GetCurrentProcess(), prioclass))
765 log_err("fio: SetPriorityClass failed\n");
770 int getrusage(int who, struct rusage *r_usage)
772 const uint64_t SECONDS_BETWEEN_1601_AND_1970 = 11644473600;
773 FILETIME cTime, eTime, kTime, uTime;
777 memset(r_usage, 0, sizeof(*r_usage));
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);
786 log_err("fio: getrusage %d is not implemented\n", who);
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
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
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;
806 int posix_madvise(void *addr, size_t len, int advice)
811 int fdatasync(int fildes)
813 return fsync(fildes);
816 ssize_t pwrite(int fildes, const void *buf, size_t nbyte,
819 int64_t pos = _telli64(fildes);
820 ssize_t len = _write(fildes, buf, nbyte);
822 _lseeki64(fildes, pos, SEEK_SET);
826 ssize_t pread(int fildes, void *buf, size_t nbyte, off_t offset)
828 int64_t pos = _telli64(fildes);
829 ssize_t len = read(fildes, buf, nbyte);
831 _lseeki64(fildes, pos, SEEK_SET);
835 ssize_t readv(int fildes, const struct iovec *iov, int iovcnt)
837 log_err("%s is not implemented\n", __func__);
842 ssize_t writev(int fildes, const struct iovec *iov, int iovcnt)
845 DWORD bytes_written = 0;
847 for (i = 0; i < iovcnt; i++) {
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);
857 bytes_written += len;
860 return bytes_written;
863 long long strtoll(const char *restrict str, char **restrict endptr, int base)
865 return _strtoi64(str, endptr, base);
868 int poll(struct pollfd fds[], nfds_t nfds, int timeout)
871 struct timeval *to = NULL;
872 fd_set readfds, writefds, exceptfds;
878 to->tv_sec = timeout / 1000;
879 to->tv_usec = (timeout % 1000) * 1000;
886 for (i = 0; i < nfds; i++) {
887 if (fds[i].fd == INVALID_SOCKET) {
892 if (fds[i].events & POLLIN)
893 FD_SET(fds[i].fd, &readfds);
895 if (fds[i].events & POLLOUT)
896 FD_SET(fds[i].fd, &writefds);
898 FD_SET(fds[i].fd, &exceptfds);
900 rc = select(nfds, &readfds, &writefds, &exceptfds, to);
902 if (rc != SOCKET_ERROR) {
903 for (i = 0; i < nfds; i++) {
904 if (fds[i].fd == INVALID_SOCKET)
907 if ((fds[i].events & POLLIN) && FD_ISSET(fds[i].fd, &readfds))
908 fds[i].revents |= POLLIN;
910 if ((fds[i].events & POLLOUT) && FD_ISSET(fds[i].fd, &writefds))
911 fds[i].revents |= POLLOUT;
913 if (FD_ISSET(fds[i].fd, &exceptfds))
914 fds[i].revents |= POLLHUP;
920 int nanosleep(const struct timespec *rqtp, struct timespec *rmtp)
924 DWORD ms_total = (rqtp->tv_sec * 1000) + (rqtp->tv_nsec / 1000000.0);
929 ms_remaining = ms_total;
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 */
934 fio_gettime(&tv, NULL);
936 ms_remaining = ms_total - mtime_since_now(&tv);
937 } while (ms_remaining > 0 && ms_remaining < ms_total);
939 /* this implementation will never sleep for less than the requested time */
948 DIR *opendir(const char *dirname)
950 struct dirent_ctx *dc = NULL;
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) {
958 dc = malloc(sizeof(struct dirent_ctx));
959 snprintf(dc->dirname, sizeof(dc->dirname), "%s", dirname);
960 dc->find_handle = INVALID_HANDLE_VALUE;
962 DWORD error = GetLastError();
963 if (error == ERROR_FILE_NOT_FOUND)
966 else if (error == ERROR_PATH_NOT_FOUND)
968 else if (error == ERROR_TOO_MANY_OPEN_FILES)
970 else if (error == ERROR_ACCESS_DENIED)
979 int closedir(DIR *dirp)
981 if (dirp != NULL && dirp->find_handle != INVALID_HANDLE_VALUE)
982 FindClose(dirp->find_handle);
988 struct dirent *readdir(DIR *dirp)
990 static struct dirent de;
991 WIN32_FIND_DATA find_data;
996 if (dirp->find_handle == INVALID_HANDLE_VALUE) {
997 char search_pattern[MAX_PATH];
999 snprintf(search_pattern, sizeof(search_pattern), "%s\\*",
1001 dirp->find_handle = FindFirstFileA(search_pattern, &find_data);
1002 if (dirp->find_handle == INVALID_HANDLE_VALUE)
1005 if (!FindNextFile(dirp->find_handle, &find_data))
1009 snprintf(de.d_name, sizeof(de.d_name), find_data.cFileName);
1017 log_err("%s is not implemented\n", __func__);
1022 in_addr_t inet_network(const char *cp)
1025 in_addr_t nbo = inet_addr(cp);
1026 hbo = ((nbo & 0xFF) << 24) + ((nbo & 0xFF00) << 8) + ((nbo & 0xFF0000) >> 8) + ((nbo & 0xFF000000) >> 24);
1030 static HANDLE create_named_pipe(char *pipe_name, int wait_connect_time)
1034 hpipe = CreateNamedPipe (
1037 PIPE_WAIT | PIPE_TYPE_BYTE,
1038 1, 0, 0, wait_connect_time, NULL);
1040 if (hpipe == INVALID_HANDLE_VALUE) {
1041 log_err("ConnectNamedPipe failed (%lu).\n", GetLastError());
1042 return INVALID_HANDLE_VALUE;
1045 if (!ConnectNamedPipe(hpipe, NULL)) {
1046 log_err("ConnectNamedPipe failed (%lu).\n", GetLastError());
1048 return INVALID_HANDLE_VALUE;
1054 static BOOL windows_create_process(PROCESS_INFORMATION *pi, const char *args, HANDLE *hjob)
1056 LPSTR this_cmd_line = GetCommandLine();
1057 LPSTR new_process_cmd_line = malloc((strlen(this_cmd_line)+strlen(args)) * sizeof(char *));
1058 STARTUPINFO si = {0};
1061 strcpy(new_process_cmd_line, this_cmd_line);
1062 strcat(new_process_cmd_line, args);
1065 memset(pi, 0, sizeof(*pi));
1067 if ((hjob != NULL) && (*hjob != INVALID_HANDLE_VALUE))
1068 flags = CREATE_SUSPENDED | CREATE_BREAKAWAY_FROM_JOB;
1070 flags |= CREATE_NEW_CONSOLE;
1072 if( !CreateProcess( NULL,
1073 new_process_cmd_line,
1074 NULL, /* Process handle not inherited */
1075 NULL, /* Thread handle not inherited */
1076 TRUE, /* no handle inheritance */
1078 NULL, /* Use parent's environment block */
1079 NULL, /* Use parent's starting directory */
1084 log_err("CreateProcess failed (%lu).\n", GetLastError() );
1085 free(new_process_cmd_line);
1088 if ((hjob != NULL) && (*hjob != INVALID_HANDLE_VALUE)) {
1089 BOOL ret = AssignProcessToJobObject(*hjob, pi->hProcess);
1091 log_err("AssignProcessToJobObject failed (%lu).\n", GetLastError() );
1095 ResumeThread(pi->hThread);
1098 free(new_process_cmd_line);
1102 HANDLE windows_create_job(void)
1104 JOBOBJECT_EXTENDED_LIMIT_INFORMATION jeli = { 0 };
1106 HANDLE hjob = CreateJobObject(NULL, NULL);
1108 jeli.BasicLimitInformation.LimitFlags = JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
1109 success = SetInformationJobObject(hjob, JobObjectExtendedLimitInformation, &jeli, sizeof(jeli));
1110 if ( success == 0 ) {
1111 log_err( "SetInformationJobObject failed: error %lu\n", GetLastError() );
1112 return INVALID_HANDLE_VALUE;
1117 /* wait for a child process to either exit or connect to a child */
1118 static bool monitor_process_till_connect(PROCESS_INFORMATION *pi, HANDLE *hpipe)
1120 bool connected = FALSE;
1121 bool process_alive = TRUE;
1122 char buffer[32] = {0};
1127 GetExitCodeProcess(pi->hProcess, &exit_code);
1128 if (exit_code != STILL_ACTIVE) {
1129 dprint(FD_PROCESS, "process %u exited %d\n", GetProcessId(pi->hProcess), exit_code);
1133 memset(buffer, 0, sizeof(buffer));
1134 ReadFile(*hpipe, &buffer, sizeof(buffer) - 1, &bytes_read, NULL);
1135 if (bytes_read && strstr(buffer, "connected")) {
1136 dprint(FD_PROCESS, "process %u connected to client\n", GetProcessId(pi->hProcess));
1140 } while (process_alive && !connected);
1144 /*create a process with --server-internal to emulate fork() */
1145 HANDLE windows_handle_connection(HANDLE hjob, int sk)
1147 char pipe_name[64] = "\\\\.\\pipe\\fiointernal-";
1148 char args[128] = " --server-internal=";
1149 PROCESS_INFORMATION pi;
1150 HANDLE hpipe = INVALID_HANDLE_VALUE;
1151 WSAPROTOCOL_INFO protocol_info;
1154 sprintf(pipe_name+strlen(pipe_name), "%d", GetCurrentProcessId());
1155 sprintf(args+strlen(args), "%s", pipe_name);
1157 if (windows_create_process(&pi, args, &hjob) != 0)
1158 return INVALID_HANDLE_VALUE;
1162 /* duplicate socket and write the protocol_info to pipe so child can
1163 * duplicate the communciation socket */
1164 if (WSADuplicateSocket(sk, GetProcessId(pi.hProcess), &protocol_info)) {
1165 log_err("WSADuplicateSocket failed (%lu).\n", GetLastError());
1166 ret = INVALID_HANDLE_VALUE;
1170 /* make a pipe with a unique name based upon processid */
1171 hpipe = create_named_pipe(pipe_name, 1000);
1172 if (hpipe == INVALID_HANDLE_VALUE) {
1173 ret = INVALID_HANDLE_VALUE;
1177 if (!WriteFile(hpipe, &protocol_info, sizeof(protocol_info), NULL, NULL)) {
1178 log_err("WriteFile failed (%lu).\n", GetLastError());
1179 ret = INVALID_HANDLE_VALUE;
1183 dprint(FD_PROCESS, "process %d created child process %u\n", GetCurrentProcessId(), GetProcessId(pi.hProcess));
1185 /* monitor the process until it either exits or connects. This level
1186 * doesnt care which of those occurs because the result is that it
1187 * needs to loop around and create another child process to monitor */
1188 if (!monitor_process_till_connect(&pi, &hpipe))
1189 ret = INVALID_HANDLE_VALUE;
1192 /* close the handles and pipes because this thread is done monitoring them */
1193 if (ret == INVALID_HANDLE_VALUE)
1194 CloseHandle(pi.hProcess);
1195 CloseHandle(pi.hThread);
1196 DisconnectNamedPipe(hpipe);