Check for __GNUC__ to use GNU C atomic buildins
[openssl.git] / crypto / threads_pthread.c
1 /*
2  * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved.
3  *
4  * Licensed under the OpenSSL license (the "License").  You may not use
5  * this file except in compliance with the License.  You can obtain a copy
6  * in the file LICENSE in the source distribution or at
7  * https://www.openssl.org/source/license.html
8  */
9
10 #include <openssl/crypto.h>
11
12 #if defined(OPENSSL_THREADS) && !defined(CRYPTO_TDEBUG) && !defined(OPENSSL_SYS_WINDOWS)
13
14 CRYPTO_RWLOCK *CRYPTO_THREAD_lock_new(void)
15 {
16     CRYPTO_RWLOCK *lock = OPENSSL_zalloc(sizeof(pthread_rwlock_t));
17     if (lock == NULL)
18         return NULL;
19
20     if (pthread_rwlock_init(lock, NULL) != 0) {
21         OPENSSL_free(lock);
22         return NULL;
23     }
24
25     return lock;
26 }
27
28 int CRYPTO_THREAD_read_lock(CRYPTO_RWLOCK *lock)
29 {
30     if (pthread_rwlock_rdlock(lock) != 0)
31         return 0;
32
33     return 1;
34 }
35
36 int CRYPTO_THREAD_write_lock(CRYPTO_RWLOCK *lock)
37 {
38     if (pthread_rwlock_wrlock(lock) != 0)
39         return 0;
40
41     return 1;
42 }
43
44 int CRYPTO_THREAD_unlock(CRYPTO_RWLOCK *lock)
45 {
46     if (pthread_rwlock_unlock(lock) != 0)
47         return 0;
48
49     return 1;
50 }
51
52 void CRYPTO_THREAD_lock_free(CRYPTO_RWLOCK *lock)
53 {
54     if (lock == NULL)
55         return;
56
57     pthread_rwlock_destroy(lock);
58     OPENSSL_free(lock);
59
60     return;
61 }
62
63 int CRYPTO_THREAD_run_once(CRYPTO_ONCE *once, void (*init)(void))
64 {
65     if (pthread_once(once, init) != 0)
66         return 0;
67
68     return 1;
69 }
70
71 int CRYPTO_THREAD_init_local(CRYPTO_THREAD_LOCAL *key, void (*cleanup)(void *))
72 {
73     if (pthread_key_create(key, cleanup) != 0)
74         return 0;
75
76     return 1;
77 }
78
79 void *CRYPTO_THREAD_get_local(CRYPTO_THREAD_LOCAL *key)
80 {
81     return pthread_getspecific(*key);
82 }
83
84 int CRYPTO_THREAD_set_local(CRYPTO_THREAD_LOCAL *key, void *val)
85 {
86     if (pthread_setspecific(*key, val) != 0)
87         return 0;
88
89     return 1;
90 }
91
92 int CRYPTO_THREAD_cleanup_local(CRYPTO_THREAD_LOCAL *key)
93 {
94     if (pthread_key_delete(*key) != 0)
95         return 0;
96
97     return 1;
98 }
99
100 CRYPTO_THREAD_ID CRYPTO_THREAD_get_current_id(void)
101 {
102     return pthread_self();
103 }
104
105 int CRYPTO_THREAD_compare_id(CRYPTO_THREAD_ID a, CRYPTO_THREAD_ID b)
106 {
107     return pthread_equal(a, b);
108 }
109
110 int CRYPTO_atomic_add(int *val, int amount, int *ret, CRYPTO_RWLOCK *lock)
111 {
112 # if defined(__GNUC__) && defined(__ATOMIC_RELAXED)
113     *ret = __atomic_add_fetch(val, amount, __ATOMIC_RELAXED);
114 # else
115     if (!CRYPTO_THREAD_write_lock(lock))
116         return 0;
117
118     *val += amount;
119     *ret  = *val;
120
121     if (!CRYPTO_THREAD_unlock(lock))
122         return 0;
123 # endif
124
125     return 1;
126 }
127
128 #endif