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#pragma once
18
19#include <platform/cbassert.h>
20
21#ifdef WIN32
22/* Include winsock2.h before windows.h to avoid winsock.h to be included */
23#include <winsock2.h>
24#include <windows.h>
25#else
26#include <pthread.h>
27#include <stdint.h>
28#ifdef __sun
29#define CB_DONT_NEED_BYTEORDER 1
30#define CB_DONT_NEED_GETHRTIME 1
31#include <sys/time.h> /* for hrtime_t */
32#endif
33#endif
34
35#include <stdio.h>
36#include <platform/visibility.h>
37
38#ifdef __APPLE__
39#include <sys/time.h>
40#endif
41
42#ifdef __cplusplus
43extern "C" {
44#endif
45
46#ifdef WIN32
47    typedef DWORD cb_thread_t;
48    typedef CRITICAL_SECTION cb_mutex_t;
49
50#ifdef _MSC_VER
51    typedef CONDITION_VARIABLE cb_cond_t;
52    typedef long ssize_t;
53#else
54    /* @TODO make sure that this buffer is big enough!!! */
55    typedef struct {
56        __int64 blob[64];
57    } cb_cond_t;
58#endif
59    typedef unsigned __int64 hrtime_t;
60
61    /* Unfortunately we don't have stdint.h on windows.. Let's just
62     * typedef them here for now.. we need to find a better solution for
63     * this!
64     */
65#if defined(_MSC_VER) && _MSC_VER < 1800
66    typedef __int8 int8_t;
67    typedef __int16 int16_t;
68    typedef __int32 int32_t;
69    typedef __int64 int64_t;
70    typedef unsigned __int8 uint8_t;
71    typedef unsigned __int16 uint16_t;
72    typedef unsigned __int32 uint32_t;
73    typedef unsigned __int64 uint64_t;
74#else
75#define CB_DONT_NEED_BYTEORDER 1
76#include <stdint.h>
77#endif
78
79#else
80    typedef pthread_t cb_thread_t;
81    typedef pthread_mutex_t cb_mutex_t;
82    typedef pthread_cond_t cb_cond_t;
83
84#ifndef __sun
85    typedef uint64_t hrtime_t;
86#endif
87
88#endif
89
90    /***********************************************************************
91     *                     Thread related functions                        *
92     **********************************************************************/
93
94    /**
95     * Thread function signature.
96     */
97    typedef void (*cb_thread_main_func)(void *argument);
98
99    /**
100     * Create a new thread (in a running state).
101     *
102     * @param id The thread identifier (returned)
103     * @param func The entry point for the newly created thread
104     * @param arg Arguments passed to the newly created thread
105     * @param detached Set to non-null if the thread should be
106     *                 created in a detached state (which you
107     *                 can't call cb_join_thread on).
108     */
109    PLATFORM_PUBLIC_API
110    int cb_create_thread(cb_thread_t *id,
111                         cb_thread_main_func func,
112                         void *arg,
113                         int detached);
114
115    /**
116     * Wait for a thread to complete
117     *
118     * @param id The thread identifier to wait for
119     */
120    PLATFORM_PUBLIC_API
121    int cb_join_thread(cb_thread_t id);
122
123    /**
124     * Get the id for the running thread
125     *
126     * @return the id for the running thread
127     */
128    PLATFORM_PUBLIC_API
129    cb_thread_t cb_thread_self(void);
130
131    /**
132     * Check if two cb_thread_t objects represent the same thread
133     *
134     * @param a the first thread
135     * @param b the second thread
136     * @return nonzero if the two objects represent the same object, 0 otherwise
137     */
138    PLATFORM_PUBLIC_API
139    int cb_thread_equal(const cb_thread_t a, const cb_thread_t b);
140
141    /***********************************************************************
142     *                      Mutex related functions                        *
143     **********************************************************************/
144    /**
145     * Initialize a mutex.
146     *
147     * We don't have <b>any</b> static initializers, so the mutex <b>must</b>
148     * be initialized by calling this function before being used.
149     *
150     * @param mutex the mutex object to initialize
151     */
152    PLATFORM_PUBLIC_API
153    void cb_mutex_initialize(cb_mutex_t *mutex);
154
155    /**
156     * Destroy (and release all allocated resources) a mutex.
157     *
158     * @param mutex the mutex object to destroy
159     */
160    PLATFORM_PUBLIC_API
161    void cb_mutex_destroy(cb_mutex_t *mutex);
162
163    /**
164     * Enter a locked section
165     *
166     * @param mutex the mutex protecting this section
167     */
168    PLATFORM_PUBLIC_API
169    void cb_mutex_enter(cb_mutex_t *mutex);
170
171    /**
172     * Try to enter a locked section
173     *
174     * @param mutex the mutex protecting this section
175     * @return 0 if the mutex was obtained, -1 otherwise
176     */
177    PLATFORM_PUBLIC_API
178    int cb_mutex_try_enter(cb_mutex_t *mutex);
179
180    /**
181     * Exit a locked section
182     *
183     * @param mutex the mutex protecting this section
184     */
185    PLATFORM_PUBLIC_API
186    void cb_mutex_exit(cb_mutex_t *mutex);
187
188    /***********************************************************************
189     *                 Condition variable related functions                *
190     **********************************************************************/
191    /**
192     * Initialize a condition variable
193     * @param cond the condition variable to initialize
194     */
195    PLATFORM_PUBLIC_API
196    void cb_cond_initialize(cb_cond_t *cond);
197
198    /**
199     * Destroy and release all allocated resources for a condition variable
200     * @param cond the condition variable to destroy
201     */
202    PLATFORM_PUBLIC_API
203    void cb_cond_destroy(cb_cond_t *cond);
204
205    /**
206     * Wait for a condition variable to be signaled.
207     *
208     * The mutex must be in a locked state, and this method will release
209     * the mutex and wait for the condition variable to be signaled in an
210     * atomic operation.
211     *
212     * The mutex is locked when the method returns.
213     *
214     * @param cond the condition variable to wait for
215     * @param mutex the locked mutex protecting the critical section
216     */
217    PLATFORM_PUBLIC_API
218    void cb_cond_wait(cb_cond_t *cond, cb_mutex_t *mutex);
219
220    /**
221     * Wait for a condition variable to be signaled, but give up after a
222     * given time.
223     *
224     * The mutex must be in a locked state, and this method will release
225     * the mutex and wait for the condition variable to be signaled in an
226     * atomic operation.
227     *
228     * The mutex is locked when the method returns.
229     *
230     * @param cond the condition variable to wait for
231     * @param mutex the locked mutex protecting the critical section
232     * @param ms the number of milliseconds to wait.
233     */
234    PLATFORM_PUBLIC_API
235    void cb_cond_timedwait(cb_cond_t *cond, cb_mutex_t *mutex, unsigned int ms);
236
237    /**
238     * Singal a single thread waiting for a condition variable
239     *
240     * @param cond the condition variable to signal
241     */
242    PLATFORM_PUBLIC_API
243    void cb_cond_signal(cb_cond_t *cond);
244
245    /**
246     * Singal all threads waiting for on condition variable
247     *
248     * @param cond the condition variable to signal
249     */
250    PLATFORM_PUBLIC_API
251    void cb_cond_broadcast(cb_cond_t *cond);
252
253
254#ifndef CB_DONT_NEED_GETHRTIME
255    /**
256     * Get a high resolution time
257     *
258     * @return number of nanoseconds since some arbitrary time in the past
259     */
260    PLATFORM_PUBLIC_API
261    hrtime_t gethrtime(void);
262#endif
263
264#ifndef CB_DONT_NEED_BYTEORDER
265    PLATFORM_PUBLIC_API
266    uint64_t ntohll(uint64_t);
267
268    PLATFORM_PUBLIC_API
269    uint64_t htonll(uint64_t);
270#endif
271
272    typedef void *cb_dlhandle_t;
273
274    PLATFORM_PUBLIC_API
275    cb_dlhandle_t cb_dlopen(const char *library, char **errmsg);
276
277    PLATFORM_PUBLIC_API
278    void *cb_dlsym(cb_dlhandle_t handle, const char *symbol, char **errmsg);
279
280    PLATFORM_PUBLIC_API
281    void cb_dlclose(cb_dlhandle_t handle);
282
283#ifdef WIN32
284    struct iovec {
285        size_t iov_len;
286        void *iov_base;
287    };
288
289    struct msghdr {
290        void *msg_name;         /* Socket name */
291        int msg_namelen;       /* Length of name */
292        struct iovec *msg_iov; /* Data blocks */
293        int msg_iovlen;        /* Number of blocks */
294    };
295
296    PLATFORM_PUBLIC_API
297    int sendmsg(SOCKET sock, const struct msghdr *msg, int flags);
298
299    /**
300     * Initialize the winsock library
301     */
302    PLATFORM_PUBLIC_API
303    void cb_initialize_sockets(void);
304
305    PLATFORM_PUBLIC_API
306    void usleep(unsigned int useconds);
307
308    PLATFORM_PUBLIC_API
309    int gettimeofday(struct timeval *tv, void *tz);
310#else
311
312#define cb_initialize_sockets()
313
314#endif
315
316    /*
317     * Set mode to binary
318     */
319    PLATFORM_PUBLIC_API
320    int platform_set_binary_mode(FILE *fp);
321
322    /*
323        return a monotonically increasing value with a seconds frequency.
324    */
325    PLATFORM_PUBLIC_API
326    uint64_t cb_get_monotonic_seconds(void);
327
328    /*
329        obtain a timeval structure containing the current time since EPOCH.
330    */
331    PLATFORM_PUBLIC_API
332    int cb_get_timeofday(struct timeval *tv);
333
334    /*
335        set an offset so that cb_get_timeofday returns an offsetted time.
336        This is intended for testing of time jumps.
337    */
338    PLATFORM_PUBLIC_API
339    void cb_set_timeofday_offset(uint64_t offset);
340
341#ifdef __cplusplus
342}
343#endif
344