1 /*
2  * Copyright (c) 2004-2005 The Trustees of Indiana University and Indiana
3  *                         University Research and Technology
4  *                         Corporation.  All rights reserved.
5  * Copyright (c) 2004-2006 The University of Tennessee and The University
6  *                         of Tennessee Research Foundation.  All rights
7  *                         reserved.
8  * Copyright (c) 2004-2005 High Performance Computing Center Stuttgart,
9  *                         University of Stuttgart.  All rights reserved.
10  * Copyright (c) 2004-2005 The Regents of the University of California.
11  *                         All rights reserved.
12  * Copyright (c) 2010      Cisco Systems, Inc. All rights reserved.
13  * Copyright (c) 2010      Oracle and/or its affiliates.  All rights reserved.
14  * Copyright (c) 2015-2017 Research Organization for Information Science
15  *                         and Technology (RIST). All rights reserved.
16  * Copyright (c) 2017-2019 Intel, Inc.  All rights reserved.
17  * $COPYRIGHT$
18  *
19  * Additional copyrights may follow
20  *
21  * $HEADER$
22  */
23 
24 #ifndef PMIX_THREAD_H
25 #define PMIX_THREAD_H 1
26 
27 #include "pmix_config.h"
28 
29 #include <pthread.h>
30 #include <signal.h>
31 
32 #include "src/class/pmix_object.h"
33 #if PMIX_ENABLE_DEBUG
34 #include "src/util/output.h"
35 #endif
36 
37 #include "mutex.h"
38 
39 BEGIN_C_DECLS
40 
41 typedef void *(*pmix_thread_fn_t) (pmix_object_t *);
42 
43 #define PMIX_THREAD_CANCELLED   ((void*)1);
44 
45 struct pmix_thread_t {
46     pmix_object_t super;
47     pmix_thread_fn_t t_run;
48     void* t_arg;
49     pthread_t t_handle;
50 };
51 
52 typedef struct pmix_thread_t pmix_thread_t;
53 
54 #if PMIX_ENABLE_DEBUG
55 PMIX_EXPORT extern bool pmix_debug_threads;
56 #endif
57 
58 
59 PMIX_EXPORT PMIX_CLASS_DECLARATION(pmix_thread_t);
60 
61 #define pmix_condition_wait(a,b)    pthread_cond_wait(a, &(b)->m_lock_pthread)
62 typedef pthread_cond_t pmix_condition_t;
63 #define pmix_condition_broadcast(a) pthread_cond_broadcast(a)
64 #define pmix_condition_signal(a)    pthread_cond_signal(a)
65 #define PMIX_CONDITION_STATIC_INIT PTHREAD_COND_INITIALIZER
66 
67 typedef struct {
68     pmix_status_t status;
69     pmix_mutex_t mutex;
70     pmix_condition_t cond;
71     volatile bool active;
72 } pmix_lock_t;
73 
74 #define PMIX_CONSTRUCT_LOCK(l)                          \
75     do {                                                \
76         PMIX_CONSTRUCT(&(l)->mutex, pmix_mutex_t);      \
77         pthread_cond_init(&(l)->cond, NULL);            \
78         /* coverity[missing_lock : FALSE] */            \
79         (l)->active = true;                             \
80     } while(0)
81 
82 #define PMIX_DESTRUCT_LOCK(l)               \
83     do {                                    \
84         PMIX_DESTRUCT(&(l)->mutex);         \
85         pthread_cond_destroy(&(l)->cond);   \
86     } while(0)
87 
88 
89 #if PMIX_ENABLE_DEBUG
90 #define PMIX_ACQUIRE_THREAD(lck)                                \
91     do {                                                        \
92         pmix_mutex_lock(&(lck)->mutex);                         \
93         if (pmix_debug_threads) {                               \
94             pmix_output(0, "Waiting for thread %s:%d",          \
95                         __FILE__, __LINE__);                    \
96         }                                                       \
97         while ((lck)->active) {                                 \
98             pmix_condition_wait(&(lck)->cond, &(lck)->mutex);   \
99         }                                                       \
100         if (pmix_debug_threads) {                               \
101             pmix_output(0, "Thread obtained %s:%d",             \
102                         __FILE__, __LINE__);                    \
103         }                                                       \
104         PMIX_ACQUIRE_OBJECT(lck);                               \
105         (lck)->active = true;                                   \
106     } while(0)
107 #else
108 #define PMIX_ACQUIRE_THREAD(lck)                                \
109     do {                                                        \
110         pmix_mutex_lock(&(lck)->mutex);                         \
111         while ((lck)->active) {                                 \
112             pmix_condition_wait(&(lck)->cond, &(lck)->mutex);   \
113         }                                                       \
114         PMIX_ACQUIRE_OBJECT(lck);                               \
115         (lck)->active = true;                                   \
116     } while(0)
117 #endif
118 
119 
120 #if PMIX_ENABLE_DEBUG
121 #define PMIX_WAIT_THREAD(lck)                                   \
122     do {                                                        \
123         pmix_mutex_lock(&(lck)->mutex);                         \
124         if (pmix_debug_threads) {                               \
125             pmix_output(0, "Waiting for thread %s:%d",          \
126                         __FILE__, __LINE__);                    \
127         }                                                       \
128         while ((lck)->active) {                                 \
129             pmix_condition_wait(&(lck)->cond, &(lck)->mutex);   \
130         }                                                       \
131         if (pmix_debug_threads) {                               \
132             pmix_output(0, "Thread obtained %s:%d",             \
133                         __FILE__, __LINE__);                    \
134         }                                                       \
135         PMIX_ACQUIRE_OBJECT(lck);                               \
136         pmix_mutex_unlock(&(lck)->mutex);                       \
137     } while(0)
138 #else
139 #define PMIX_WAIT_THREAD(lck)                                   \
140     do {                                                        \
141         pmix_mutex_lock(&(lck)->mutex);                         \
142         while ((lck)->active) {                                 \
143             pmix_condition_wait(&(lck)->cond, &(lck)->mutex);   \
144         }                                                       \
145         PMIX_ACQUIRE_OBJECT(lck);                               \
146         pmix_mutex_unlock(&(lck)->mutex);                       \
147     } while(0)
148 #endif
149 
150 
151 #if PMIX_ENABLE_DEBUG
152 #define PMIX_RELEASE_THREAD(lck)                        \
153     do {                                                \
154         if (pmix_debug_threads) {                       \
155             pmix_output(0, "Releasing thread %s:%d",    \
156                         __FILE__, __LINE__);            \
157         }                                               \
158         (lck)->active = false;                          \
159         PMIX_POST_OBJECT(lck);                  \
160         pmix_condition_broadcast(&(lck)->cond);         \
161         pmix_mutex_unlock(&(lck)->mutex);               \
162     } while(0)
163 #else
164 #define PMIX_RELEASE_THREAD(lck)                \
165     do {                                        \
166         (lck)->active = false;                  \
167         PMIX_POST_OBJECT(lck);                  \
168         pmix_condition_broadcast(&(lck)->cond); \
169         pmix_mutex_unlock(&(lck)->mutex);       \
170     } while(0)
171 #endif
172 
173 
174 #define PMIX_WAKEUP_THREAD(lck)                 \
175     do {                                        \
176         pmix_mutex_lock(&(lck)->mutex);         \
177         (lck)->active = false;                  \
178         PMIX_POST_OBJECT(lck);                  \
179         pmix_condition_broadcast(&(lck)->cond); \
180         pmix_mutex_unlock(&(lck)->mutex);       \
181     } while(0)
182 
183 
184 /* provide a macro for forward-proofing the shifting
185  * of objects between threads - at some point, we
186  * may revamp our threading model */
187 
188 /* post an object to another thread - for now, we
189  * only have a memory barrier */
190 #define PMIX_POST_OBJECT(o)     pmix_atomic_wmb()
191 
192 /* acquire an object from another thread - for now,
193  * we only have a memory barrier */
194 #define PMIX_ACQUIRE_OBJECT(o)  pmix_atomic_rmb()
195 
196 
197 PMIX_EXPORT int  pmix_thread_start(pmix_thread_t *);
198 PMIX_EXPORT int  pmix_thread_join(pmix_thread_t *, void **thread_return);
199 PMIX_EXPORT bool pmix_thread_self_compare(pmix_thread_t*);
200 PMIX_EXPORT pmix_thread_t *pmix_thread_get_self(void);
201 PMIX_EXPORT void pmix_thread_kill(pmix_thread_t *, int sig);
202 PMIX_EXPORT void pmix_thread_set_main(void);
203 
204 END_C_DECLS
205 
206 #endif /* PMIX_THREAD_H */
207