xref: /4.0.0/platform/src/cb_win32.c (revision 0d1de5db)
1/* -*- Mode: C; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2/*
3 *     Copyright 2013 Couchbase, Inc.
4 *
5 *   Licensed under the Apache License, Version 2.0 (the "License");
6 *   you may not use this file except in compliance with the License.
7 *   You may obtain a copy of the License at
8 *
9 *       http://www.apache.org/licenses/LICENSE-2.0
10 *
11 *   Unless required by applicable law or agreed to in writing, software
12 *   distributed under the License is distributed on an "AS IS" BASIS,
13 *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 *   See the License for the specific language governing permissions and
15 *   limitations under the License.
16 */
17#include "config.h"
18#include <assert.h>
19#include <stdio.h>
20#include <fcntl.h>
21#include <io.h>
22
23struct thread_execute {
24    cb_thread_main_func func;
25    void *argument;
26};
27
28static DWORD WINAPI platform_thread_wrap(LPVOID arg)
29{
30    struct thread_execute *ctx = arg;
31    assert(ctx);
32    ctx->func(ctx->argument);
33    free(ctx);
34    return 0;
35}
36
37
38__declspec(dllexport)
39int cb_create_thread(cb_thread_t *id,
40                     void (*func)(void *arg),
41                     void *arg,
42                     int detached)
43{
44    HANDLE handle;
45    struct thread_execute *ctx = malloc(sizeof(struct thread_execute));
46    if (ctx == NULL) {
47        return -1;
48    }
49
50    ctx->func = func;
51    ctx->argument = arg;
52
53    handle = CreateThread(NULL, 0, platform_thread_wrap, ctx, 0, id);
54    if (handle == NULL) {
55        free(ctx);
56        return -1;
57    } else {
58        if (detached) {
59            CloseHandle(handle);
60        }
61    }
62
63    return 0;
64}
65
66__declspec(dllexport)
67int cb_create_named_thread(cb_thread_t *id, void (*func)(void *arg), void *arg,
68                     int detached, const char* name)
69{
70    // Thread naming not supported on WIN32, just call down to non-named
71    // variant.
72    return cb_create_thread(id, func, arg, detached);
73}
74
75__declspec(dllexport)
76int cb_join_thread(cb_thread_t id)
77{
78    HANDLE handle = OpenThread(SYNCHRONIZE, FALSE, id);
79    if (handle == NULL) {
80        return -1;
81    }
82    WaitForSingleObject(handle, INFINITE);
83    CloseHandle(handle);
84    return 0;
85}
86
87__declspec(dllexport)
88cb_thread_t cb_thread_self(void)
89{
90    return GetCurrentThreadId();
91}
92
93__declspec(dllexport)
94int cb_thread_equal(const cb_thread_t a, const cb_thread_t b)
95{
96    return a == b;
97}
98
99__declspec(dllexport)
100void cb_set_thread_name(const char* name)
101{
102    // Not implemented on WIN32
103    (void)name;
104}
105
106__declspec(dllexport)
107void cb_mutex_initialize(cb_mutex_t *mutex)
108{
109    InitializeCriticalSection(mutex);
110}
111
112__declspec(dllexport)
113void cb_mutex_destroy(cb_mutex_t *mutex)
114{
115    DeleteCriticalSection(mutex);
116}
117
118__declspec(dllexport)
119void cb_mutex_enter(cb_mutex_t *mutex)
120{
121    EnterCriticalSection(mutex);
122}
123
124__declspec(dllexport)
125int cb_mutex_try_enter(cb_mutex_t *mutex)
126{
127    return TryEnterCriticalSection(mutex) ? 0 : -1;
128}
129
130__declspec(dllexport)
131void cb_mutex_exit(cb_mutex_t *mutex)
132{
133    LeaveCriticalSection(mutex);
134}
135
136__declspec(dllexport)
137void cb_cond_initialize(cb_cond_t *cond)
138{
139    InitializeConditionVariable(cond);
140}
141
142__declspec(dllexport)
143void cb_cond_destroy(cb_cond_t *cond)
144{
145    (void)cond;
146}
147
148__declspec(dllexport)
149void cb_cond_wait(cb_cond_t *cond, cb_mutex_t *mutex)
150{
151    SleepConditionVariableCS(cond, mutex, INFINITE);
152}
153
154__declspec(dllexport)
155void cb_cond_timedwait(cb_cond_t *cond, cb_mutex_t *mutex, unsigned int msec) {
156    SleepConditionVariableCS(cond, mutex, msec);
157}
158
159__declspec(dllexport)
160void cb_cond_signal(cb_cond_t *cond)
161{
162    WakeConditionVariable(cond);
163}
164
165__declspec(dllexport)
166void cb_cond_broadcast(cb_cond_t *cond)
167{
168    WakeAllConditionVariable(cond);
169}
170
171static const char *get_dll_name(const char *path, char *buffer)
172{
173    char *ptr = strstr(path, ".dll");
174    if (ptr != NULL) {
175        return path;
176    }
177
178    strcpy(buffer, path);
179
180    ptr = strstr(buffer, ".so");
181    if (ptr != NULL) {
182        sprintf(ptr, ".dll");
183        return buffer;
184    }
185
186    strcat(buffer, ".dll");
187    return buffer;
188}
189
190__declspec(dllexport)
191cb_dlhandle_t cb_dlopen(const char *library, char **errmsg)
192{
193    cb_dlhandle_t handle;
194    char *buffer;
195
196    if (library == NULL) {
197        if (errmsg != NULL) {
198            *errmsg = _strdup("Open self is not supported");
199        }
200        return NULL;
201    }
202
203    buffer = malloc(strlen(library) + 20);
204    if (buffer == NULL) {
205        if (*errmsg) {
206            *errmsg = _strdup("Failed to allocate memory");
207        }
208        return NULL;
209    }
210
211    handle = LoadLibrary(get_dll_name(library, buffer));
212    if (handle == NULL && errmsg != NULL) {
213        DWORD err = GetLastError();
214        LPVOID error_msg;
215
216        if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
217                          FORMAT_MESSAGE_FROM_SYSTEM |
218                          FORMAT_MESSAGE_IGNORE_INSERTS,
219                          NULL, err, 0, (LPTSTR)&error_msg, 0, NULL) != 0) {
220            *errmsg = _strdup(error_msg);
221            LocalFree(error_msg);
222        } else {
223            *errmsg = _strdup("Failed to get error message");
224        }
225    }
226
227    free(buffer);
228
229    return handle;
230}
231
232__declspec(dllexport)
233void *cb_dlsym(cb_dlhandle_t handle, const char *symbol, char **errmsg)
234{
235    void *ret = GetProcAddress(handle, symbol);
236    if (ret == NULL && errmsg) {
237        DWORD err = GetLastError();
238        LPVOID error_msg;
239
240        if (FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER |
241                          FORMAT_MESSAGE_FROM_SYSTEM |
242                          FORMAT_MESSAGE_IGNORE_INSERTS,
243                          NULL, err, 0, (LPTSTR)&error_msg, 0, NULL) != 0) {
244            *errmsg = _strdup(error_msg);
245            LocalFree(error_msg);
246        } else {
247            *errmsg = _strdup("Failed to get error message");
248        }
249    }
250
251    return ret;
252}
253
254__declspec(dllexport)
255void cb_dlclose(cb_dlhandle_t handle)
256{
257    FreeLibrary(handle);
258}
259
260__declspec(dllexport)
261void usleep(unsigned int useconds)
262{
263    unsigned int msec = useconds / 1000;
264    if (msec == 0) {
265        msec = 1;
266    }
267    Sleep(msec);
268}
269
270__declspec(dllexport)
271int gettimeofday(struct timeval *tv, void *tz)
272{
273    FILETIME ft;
274    uint64_t usecs;
275    LARGE_INTEGER li;
276    uint64_t secs;
277
278    assert(tz == NULL); /* I don't support that right now */
279    assert(tv != NULL); /* I don't support that right now */
280
281    GetSystemTimeAsFileTime(&ft);
282    li.LowPart = ft.dwLowDateTime;
283    li.HighPart = ft.dwHighDateTime;
284    usecs = li.QuadPart;
285
286    // FILETIME is 100 nanosecs from from 1. jan 1601
287    // convert it to usecs..
288    usecs /= 10;
289
290    secs = usecs / 1000000;
291    tv->tv_usec = usecs % 1000000;
292
293    // gettimeofday use 1st january 1970, subtract the secs
294    // between the dates
295    secs -= 11644473600;
296    tv->tv_sec = (unsigned long)secs;
297
298    return 0;
299}
300
301__declspec(dllexport)
302int platform_set_binary_mode(FILE *fp)
303{
304    return _setmode(_fileno(fp), _O_BINARY);
305}
306