Fork of Tangara with customizations
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 
tangara-fw/lib/lua-linenoise/win32fixes.c

539 lines
15 KiB

/*
* 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 <process.h>
#include <stdlib.h>
#include <errno.h>
#ifndef FD_SETSIZE
#define FD_SETSIZE 16000
#endif
#include <winsock2.h>
#include <windows.h>
#include <signal.h>
#include <time.h>
#include <locale.h>
#include <math.h>
#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