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