/* * Modified by Henry Rawas (henryr@schakra.com) * - make it compatible with Visual Studio builds * - added wstrtod to handle INF, NAN * - added gettimeofday routine * - modified rename to retry after failure */ #if defined(_WIN32) && !defined(__MINGW32__) /* MinGW doesn't like this file */ #include #include #include #ifndef FD_SETSIZE #define FD_SETSIZE 16000 #endif #include #include #include #include #include #include #include "win32fixes.h" /* Redefined here to avoid redis.h so it can be used in other projects */ #define REDIS_NOTUSED(V) ((void) V) #define REDIS_THREAD_STACK_SIZE (1024*1024*4) /* Winsock requires library initialization on startup */ int w32initWinSock(void) { WSADATA t_wsa; WORD wVers; int iError; wVers = MAKEWORD(2, 2); iError = WSAStartup(wVers, &t_wsa); if(iError != NO_ERROR || LOBYTE(t_wsa.wVersion) != 2 || HIBYTE(t_wsa.wVersion) != 2 ) { return 0; /* not done; check WSAGetLastError() for error number */ }; return 1; } /* Behaves as posix, works without ifdefs, makes compiler happy */ int sigaction(int sig, struct sigaction *in, struct sigaction *out) { REDIS_NOTUSED(out); /* When the SA_SIGINFO flag is set in sa_flags then sa_sigaction * is used. Otherwise, sa_handler is used */ if (in->sa_flags & SA_SIGINFO) signal(sig, in->sa_sigaction); else signal(sig, in->sa_handler); return 0; } /* Terminates process, implemented only for SIGKILL */ int kill(pid_t pid, int sig) { if (sig == SIGKILL) { HANDLE h = OpenProcess(PROCESS_TERMINATE, 0, pid); if (!TerminateProcess(h, 127)) { errno = EINVAL; /* GetLastError() */ CloseHandle(h); return -1; }; CloseHandle(h); return 0; } else { errno = EINVAL; return -1; }; } /* Forced write to disk */ int fsync (int fd) { HANDLE h = (HANDLE) _get_osfhandle(fd); DWORD err; if (h == INVALID_HANDLE_VALUE) { errno = EBADF; return -1; } if (!FlushFileBuffers(h)) { /* Windows error -> Unix */ err = GetLastError(); switch (err) { case ERROR_INVALID_HANDLE: errno = EINVAL; break; default: errno = EIO; } return -1; } return 0; } /* Missing wait3() implementation */ pid_t wait3(int *stat_loc, int options, void *rusage) { REDIS_NOTUSED(stat_loc); REDIS_NOTUSED(options); REDIS_NOTUSED(rusage); return (pid_t) waitpid((intptr_t) -1, 0, WAIT_FLAGS); } /* Replace MS C rtl rand which is 15bit with 32 bit */ int replace_random() { unsigned int x=0; if (RtlGenRandom == NULL) { // load proc if not loaded HMODULE lib = LoadLibraryA("advapi32.dll"); RtlGenRandom = (RtlGenRandomFunc)GetProcAddress(lib, "SystemFunction036"); if (RtlGenRandom == NULL) return 1; } RtlGenRandom(&x, sizeof(UINT_MAX)); return (int)(x >> 1); } /* BSD sockets compatibile replacement */ int replace_setsockopt(int socket, int level, int optname, const void *optval, socklen_t optlen) { return (setsockopt)((SOCKET)socket, level, optname, (const char *)optval, optlen); } /* set size with 64bit support */ int replace_ftruncate(int fd, off64_t length) { HANDLE h = (HANDLE) _get_osfhandle (fd); LARGE_INTEGER l, o; if (h == INVALID_HANDLE_VALUE) { errno = EBADF; return -1; } l.QuadPart = length; if (!SetFilePointerEx(h, l, &o, FILE_BEGIN)) return -1; if (!SetEndOfFile(h)) return -1; return 0; } /* Rename which works on Windows when file exists */ int replace_rename(const char *src, const char *dst) { /* anti-virus may lock file - error code 5. Retry until it works or get a different error */ int retries = 50; while (1) { if (MoveFileEx(src, dst, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED | MOVEFILE_WRITE_THROUGH)) { return 0; } else { errno = GetLastError(); if (errno != 5) break; retries--; if (retries == 0) { retries = 50; Sleep(10); } } } /* On error we will return generic error code without GetLastError() */ return -1; } /* Proxy structure to pass func and arg to thread */ typedef struct thread_params { void *(*func)(void *); void * arg; } thread_params; /* Proxy function by windows thread requirements */ static unsigned __stdcall win32_proxy_threadproc(void *arg) { thread_params *p = (thread_params *) arg; p->func(p->arg); /* Dealocate params */ free(p); _endthreadex(0); return 0; } int pthread_create(pthread_t *thread, const void *unused, void *(*start_routine)(void*), void *arg) { HANDLE h; thread_params *params = (thread_params *)malloc(sizeof(thread_params)); REDIS_NOTUSED(unused); params->func = start_routine; params->arg = arg; h =(HANDLE) _beginthreadex(NULL, /* Security not used */ REDIS_THREAD_STACK_SIZE, /* Set custom stack size */ win32_proxy_threadproc, /* calls win32 stdcall proxy */ params, /* real threadproc is passed as paremeter */ STACK_SIZE_PARAM_IS_A_RESERVATION, /* reserve stack */ thread /* returned thread id */ ); if (!h) return errno; CloseHandle(h); return 0; } /* Noop in windows */ int pthread_detach (pthread_t thread) { REDIS_NOTUSED(thread); return 0; /* noop */ } pthread_t pthread_self(void) { return GetCurrentThreadId(); } int win32_pthread_join(pthread_t *thread, void **value_ptr) { int result; HANDLE h = OpenThread(SYNCHRONIZE, FALSE, *thread); REDIS_NOTUSED(value_ptr); switch (WaitForSingleObject(h, INFINITE)) { case WAIT_OBJECT_0: result = 0; case WAIT_ABANDONED: result = EINVAL; default: result = GetLastError(); } CloseHandle(h); return result; } int pthread_cond_init(pthread_cond_t *cond, const void *unused) { REDIS_NOTUSED(unused); cond->waiters = 0; cond->was_broadcast = 0; InitializeCriticalSection(&cond->waiters_lock); cond->sema = CreateSemaphore(NULL, 0, LONG_MAX, NULL); if (!cond->sema) { errno = GetLastError(); return -1; } cond->continue_broadcast = CreateEvent(NULL, /* security */ FALSE, /* auto-reset */ FALSE, /* not signaled */ NULL); /* name */ if (!cond->continue_broadcast) { errno = GetLastError(); return -1; } return 0; } int pthread_cond_destroy(pthread_cond_t *cond) { CloseHandle(cond->sema); CloseHandle(cond->continue_broadcast); DeleteCriticalSection(&cond->waiters_lock); return 0; } int pthread_cond_wait(pthread_cond_t *cond, pthread_mutex_t *mutex) { int last_waiter; EnterCriticalSection(&cond->waiters_lock); cond->waiters++; LeaveCriticalSection(&cond->waiters_lock); /* * Unlock external mutex and wait for signal. * NOTE: we've held mutex locked long enough to increment * waiters count above, so there's no problem with * leaving mutex unlocked before we wait on semaphore. */ LeaveCriticalSection(mutex); /* let's wait - ignore return value */ WaitForSingleObject(cond->sema, INFINITE); /* * Decrease waiters count. If we are the last waiter, then we must * notify the broadcasting thread that it can continue. * But if we continued due to cond_signal, we do not have to do that * because the signaling thread knows that only one waiter continued. */ EnterCriticalSection(&cond->waiters_lock); cond->waiters--; last_waiter = cond->was_broadcast && cond->waiters == 0; LeaveCriticalSection(&cond->waiters_lock); if (last_waiter) { /* * cond_broadcast was issued while mutex was held. This means * that all other waiters have continued, but are contending * for the mutex at the end of this function because the * broadcasting thread did not leave cond_broadcast, yet. * (This is so that it can be sure that each waiter has * consumed exactly one slice of the semaphor.) * The last waiter must tell the broadcasting thread that it * can go on. */ SetEvent(cond->continue_broadcast); /* * Now we go on to contend with all other waiters for * the mutex. Auf in den Kampf! */ } /* lock external mutex again */ EnterCriticalSection(mutex); return 0; } /* * IMPORTANT: This implementation requires that pthread_cond_signal * is called while the mutex is held that is used in the corresponding * pthread_cond_wait calls! */ int pthread_cond_signal(pthread_cond_t *cond) { int have_waiters; EnterCriticalSection(&cond->waiters_lock); have_waiters = cond->waiters > 0; LeaveCriticalSection(&cond->waiters_lock); /* * Signal only when there are waiters */ if (have_waiters) return ReleaseSemaphore(cond->sema, 1, NULL) ? 0 : GetLastError(); else return 0; } /* Redis forks to perform background writing */ /* fork() on unix will split process in two */ /* marking memory pages as Copy-On-Write so */ /* child process will have data snapshot. */ /* Windows has no support for fork(). */ int fork(void) { return -1; } /* Redis CPU GetProcessTimes -> rusage */ int getrusage(int who, struct rusage * r) { FILETIME starttime, exittime, kerneltime, usertime; ULARGE_INTEGER li; if (r == NULL) { errno = EFAULT; return -1; } memset(r, 0, sizeof(struct rusage)); if (who == RUSAGE_SELF) { if (!GetProcessTimes(GetCurrentProcess(), &starttime, &exittime, &kerneltime, &usertime)) { errno = EFAULT; return -1; } } if (who == RUSAGE_CHILDREN) { /* Childless on windows */ starttime.dwLowDateTime = 0; starttime.dwHighDateTime = 0; exittime.dwLowDateTime = 0; exittime.dwHighDateTime = 0; kerneltime.dwLowDateTime = 0; kerneltime.dwHighDateTime = 0; usertime.dwLowDateTime = 0; usertime.dwHighDateTime = 0; } memcpy(&li, &kerneltime, sizeof(FILETIME)); li.QuadPart /= 10L; r->ru_stime.tv_sec = (long)(li.QuadPart / 1000000L); r->ru_stime.tv_usec = (long)(li.QuadPart % 1000000L); memcpy(&li, &usertime, sizeof(FILETIME)); li.QuadPart /= 10L; r->ru_utime.tv_sec = (long)(li.QuadPart / 1000000L); r->ru_utime.tv_usec = (long)(li.QuadPart % 1000000L); return 0; } #define DELTA_EPOCH_IN_MICROSECS 11644473600000000Ui64 struct timezone { int tz_minuteswest; /* minutes W of Greenwich */ int tz_dsttime; /* type of dst correction */ }; int gettimeofday(struct timeval *tv, struct timezone *tz) { FILETIME ft; unsigned __int64 tmpres = 0; static int tzflag; if (NULL != tv) { GetSystemTimeAsFileTime(&ft); tmpres |= ft.dwHighDateTime; tmpres <<= 32; tmpres |= ft.dwLowDateTime; /*converting file time to unix epoch*/ tmpres -= DELTA_EPOCH_IN_MICROSECS; tmpres /= 10; /*convert into microseconds*/ tv->tv_sec = (long)(tmpres / 1000000UL); tv->tv_usec = (long)(tmpres % 1000000UL); } if (NULL != tz) { if (!tzflag) { _tzset(); tzflag++; } tz->tz_minuteswest = _timezone / 60; tz->tz_dsttime = _daylight; } return 0; } static _locale_t clocale = NULL; double wstrtod(const char *nptr, char **eptr) { double d; char *leptr; if (clocale == NULL) clocale = _create_locale(LC_ALL, "C"); d = _strtod_l(nptr, &leptr, clocale); /* if 0, check if input was inf */ if (d == 0 && nptr == leptr) { int neg = 0; while (isspace(*nptr)) nptr++; if (*nptr == '+') nptr++; else if (*nptr == '-') { nptr++; neg = 1; } if (strnicmp("INF", nptr, 3) == 0) { if (eptr != NULL) { if (strnicmp("INFINITE", nptr, 8) == 0) *eptr = (char*)(nptr + 8); else *eptr = (char*)(nptr + 3); } if (neg == 1) return -HUGE_VAL; else return HUGE_VAL; } else if (strnicmp("NAN", nptr, 3) == 0) { if (eptr != NULL) *eptr = (char*)(nptr + 3); /* create a NaN : 0 * infinity*/ d = HUGE_VAL; return d * 0; } } if (eptr != NULL) *eptr = leptr; return d; } int strerror_r(int err, char* buf, size_t buflen) { int size = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, 0, buf, (DWORD)buflen, NULL); if (size == 0) { char* strerr = strerror(err); if (strlen(strerr) >= buflen) { errno = ERANGE; return -1; } strcpy(buf, strerr); } if (size > 2 && buf[size - 2] == '\r') { /* remove extra CRLF */ buf[size - 2] = '\0'; } return 0; } char wsa_strerror_buf[128]; char *wsa_strerror(int err) { int size = FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS, NULL, err, 0, wsa_strerror_buf, 128, NULL); if (size == 0) return strerror(err); if (size > 2 && wsa_strerror_buf[size - 2] == '\r') { /* remove extra CRLF */ wsa_strerror_buf[size - 2] = '\0'; } return wsa_strerror_buf; } #endif