Adds writer test case for RCU
[folly.git] / folly / portability / PThread.h
1 /*
2  * Copyright 2016-present Facebook, 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 #pragma once
18
19 #include <folly/portability/Config.h>
20
21 #if !defined(_WIN32)
22
23 #include <pthread.h> // nolint
24
25 #elif !FOLLY_HAVE_PTHREAD
26
27 #include <folly/portability/Windows.h> // nolint
28 #include <cstdint>
29
30 namespace folly {
31 namespace portability {
32 namespace pthread {
33 using pthread_key_t = DWORD;
34
35 int pthread_key_create(pthread_key_t* key, void (*destructor)(void*));
36 int pthread_key_delete(pthread_key_t key);
37 void* pthread_getspecific(pthread_key_t key);
38 int pthread_setspecific(pthread_key_t key, const void* value);
39 }
40 }
41 }
42
43 /* using override */ using namespace folly::portability::pthread;
44
45 #else
46 // The pthread implementation we support on Windows is a bit of a pain to work
47 // with in certain places. This entire mess here exists for exactly one reason:
48 // `using pid_t = int;`
49 // Without all of this mess, the pthread implementation will attempt to define
50 // `pid_t` as `void*` which is incompatible with just about every other
51 // definition of `pid_t` used by other libraries defining it on Windows, for
52 // example, python.
53
54 // On Windows, define mode_t and pid_t
55 #include <folly/portability/SysTypes.h>
56
57 // HANDLE and DWORD for the declarations further down.
58 #include <folly/portability/Windows.h> // nolint
59
60 // Because of INCLUDE_NP, `errno.h` doesn't get included by pthread, causing it
61 // to define the errno values itself, which causes conflicts when `errno.h` ends
62 // up actually getting included, so we include it explicitly here to prevent it
63 // from defining the values itself.
64 #include <errno.h>
65
66 // Pretend we are building with AT&T's UWIN project, which is a Unix API for
67 // Windows 95 & Windows NT. Yes, really. https://github.com/att/uwin
68 // This is the core define that keeps `pthread.h` from defining `pid_t`.
69 #define _UWIN 1
70
71 // Because we've defined `_UWIN`, the pthread implementation thinks that the
72 // pthread types have all also already been defined by default. By defining
73 // this, we force `PTW32_LEVEL` to be defined as `2`, which is enough to get it
74 // to define the pthread types for us.
75 #define INCLUDE_NP 1
76
77 // By defining `_UWIN` we cause the pthread implementation to aggressively
78 // define `HAVE_MODE_T`, which we define in `folly/portability/SysTypes.h` to
79 // keep it from defining an incompatible version of it. We undefine the macro
80 // here to keep from generating warnings when the implementation defines it.
81 // Note that the implementation leaks its definition of `HAVE_MODE_T`, so we
82 // don't need to re-define it after.
83 #undef HAVE_MODE_T
84
85 #include <pthread.h> // nolint
86
87 #ifndef HAVE_MODE_T
88 #error We expected pthread.h to define HAVE_MODE_T but that did not happen.
89 #endif
90
91 // Now clean up our mess so nothing else thinks we're doing crazy things.
92 #undef _UWIN
93 #undef INCLUDE_NP
94
95 // Because we defined `INCLUDE_NP` above, the non-portable APIs don't actually
96 // get declared. We still need them, so declare them ourselves instead.
97 PTW32_DLLPORT HANDLE PTW32_CDECL
98 pthread_getw32threadhandle_np(pthread_t thread);
99 PTW32_DLLPORT DWORD PTW32_CDECL pthread_getw32threadid_np(pthread_t thread);
100
101 // And now everything else that isn't just here for `pid_t`.
102
103 // We implement a sane comparison operand for
104 // pthread_t and an integer so that it may be
105 // compared against 0.
106 inline bool operator==(pthread_t ptA, unsigned int b) {
107   if (ptA.p == nullptr) {
108     return b == 0;
109   }
110   return pthread_getw32threadid_np(ptA) == b;
111 }
112
113 inline bool operator!=(pthread_t ptA, unsigned int b) {
114   if (ptA.p == nullptr) {
115     return b != 0;
116   }
117   return pthread_getw32threadid_np(ptA) != b;
118 }
119
120 inline bool operator==(pthread_t ptA, pthread_t ptB) {
121   return pthread_equal(ptA, ptB) != 0;
122 }
123
124 inline bool operator!=(pthread_t ptA, pthread_t ptB) {
125   return pthread_equal(ptA, ptB) == 0;
126 }
127
128 inline bool operator<(pthread_t ptA, pthread_t ptB) {
129   return ptA.p < ptB.p;
130 }
131
132 inline bool operator!(pthread_t ptA) {
133   return ptA == 0;
134 }
135
136 inline int pthread_attr_getstack(
137     pthread_attr_t* attr,
138     void** stackaddr,
139     size_t* stacksize) {
140   if (pthread_attr_getstackaddr(attr, stackaddr) != 0) {
141     return -1;
142   }
143   if (pthread_attr_getstacksize(attr, stacksize) != 0) {
144     return -1;
145   }
146   return 0;
147 }
148
149 inline int
150 pthread_attr_setstack(pthread_attr_t* attr, void* stackaddr, size_t stacksize) {
151   if (pthread_attr_setstackaddr(attr, stackaddr) != 0) {
152     return -1;
153   }
154   if (pthread_attr_setstacksize(attr, stacksize) != 0) {
155     return -1;
156   }
157   return 0;
158 }
159
160 inline int pthread_attr_getguardsize(
161     pthread_attr_t* /* attr */,
162     size_t* guardsize) {
163   *guardsize = 0;
164   return 0;
165 }
166
167 #include <functional>
168 namespace std {
169 template <>
170 struct hash<pthread_t> {
171   std::size_t operator()(const pthread_t& k) const {
172     return 0 ^ std::hash<decltype(k.p)>()(k.p) ^
173         std::hash<decltype(k.x)>()(k.x);
174   }
175 };
176 }
177 #endif