ovs-thread: Add support for convenient once-only initializers.
[sliver-openvswitch.git] / lib / ovs-thread.c
1 /*
2  * Copyright (c) 2013 Nicira, Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at:
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include <config.h>
18 #include "ovs-thread.h"
19 #include <errno.h>
20 #include "compiler.h"
21 #include "util.h"
22
23 #ifdef __CHECKER__
24 /* Omit the definitions in this file because they are somewhat difficult to
25  * write without prompting "sparse" complaints, without ugliness or
26  * cut-and-paste.  Since "sparse" is just a checker, not a compiler, it
27  * doesn't matter that we don't define them. */
28 #else
29 #define XPTHREAD_FUNC1(FUNCTION, PARAM1)                \
30     void                                                \
31     x##FUNCTION(PARAM1 arg1)                            \
32     {                                                   \
33         int error = FUNCTION(arg1);                     \
34         if (OVS_UNLIKELY(error)) {                      \
35             ovs_abort(error, "%s failed", #FUNCTION);   \
36         }                                               \
37     }
38 #define XPTHREAD_TRY_FUNC1(FUNCTION, PARAM1)            \
39     int                                                 \
40     x##FUNCTION(PARAM1 arg1)                            \
41     {                                                   \
42         int error = FUNCTION(arg1);                     \
43         if (OVS_UNLIKELY(error && error != EBUSY)) {    \
44             ovs_abort(error, "%s failed", #FUNCTION);   \
45         }                                               \
46         return error;                                   \
47     }
48 #define XPTHREAD_FUNC2(FUNCTION, PARAM1, PARAM2)        \
49     void                                                \
50     x##FUNCTION(PARAM1 arg1, PARAM2 arg2)               \
51     {                                                   \
52         int error = FUNCTION(arg1, arg2);               \
53         if (OVS_UNLIKELY(error)) {                      \
54             ovs_abort(error, "%s failed", #FUNCTION);   \
55         }                                               \
56     }
57
58 XPTHREAD_FUNC2(pthread_mutex_init, pthread_mutex_t *, pthread_mutexattr_t *);
59 XPTHREAD_FUNC1(pthread_mutex_lock, pthread_mutex_t *);
60 XPTHREAD_FUNC1(pthread_mutex_unlock, pthread_mutex_t *);
61 XPTHREAD_TRY_FUNC1(pthread_mutex_trylock, pthread_mutex_t *);
62
63 XPTHREAD_FUNC2(pthread_rwlock_init,
64                pthread_rwlock_t *, pthread_rwlockattr_t *);
65 XPTHREAD_FUNC1(pthread_rwlock_rdlock, pthread_rwlock_t *);
66 XPTHREAD_FUNC1(pthread_rwlock_wrlock, pthread_rwlock_t *);
67 XPTHREAD_FUNC1(pthread_rwlock_unlock, pthread_rwlock_t *);
68 XPTHREAD_TRY_FUNC1(pthread_rwlock_tryrdlock, pthread_rwlock_t *);
69 XPTHREAD_TRY_FUNC1(pthread_rwlock_trywrlock, pthread_rwlock_t *);
70
71 XPTHREAD_FUNC2(pthread_cond_init, pthread_cond_t *, pthread_condattr_t *);
72 XPTHREAD_FUNC1(pthread_cond_signal, pthread_cond_t *);
73 XPTHREAD_FUNC1(pthread_cond_broadcast, pthread_cond_t *);
74 XPTHREAD_FUNC2(pthread_cond_wait, pthread_cond_t *, pthread_mutex_t *);
75
76 typedef void destructor_func(void *);
77 XPTHREAD_FUNC2(pthread_key_create, pthread_key_t *, destructor_func *);
78
79 void
80 xpthread_create(pthread_t *threadp, pthread_attr_t *attr,
81                 void *(*start)(void *), void *arg)
82 {
83     pthread_t thread;
84     int error;
85
86     error = pthread_create(threadp ? threadp : &thread, attr, start, arg);
87     if (error) {
88         ovs_abort(error, "pthread_create failed");
89     }
90 }
91 \f
92 bool
93 ovsthread_once_start__(struct ovsthread_once *once)
94 {
95     xpthread_mutex_lock(&once->mutex);
96     if (!ovsthread_once_is_done__(once)) {
97         return false;
98     }
99     xpthread_mutex_unlock(&once->mutex);
100     return true;
101 }
102
103 void OVS_RELEASES(once)
104 ovsthread_once_done(struct ovsthread_once *once)
105 {
106     atomic_store(&once->done, true);
107     xpthread_mutex_unlock(&once->mutex);
108 }
109 #endif