1 /*
2  * %CopyrightBegin%
3  *
4  * Copyright Ericsson AB 2007-2018. All Rights Reserved.
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  *     http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  *
18  * %CopyrightEnd%
19  */
20 
21 
22 /*
23  * Description:	Impementation of Erlang process locks.
24  *
25  * Author: 	Rickard Green
26  */
27 
28 #ifndef ERTS_PROC_LOCK_TYPE__
29 #define ERTS_PROC_LOCK_TYPE__
30 
31 #ifdef ERTS_ENABLE_LOCK_CHECK
32 #define ERTS_PROC_LOCK_DEBUG
33 #endif
34 
35 #ifdef ERTS_ENABLE_LOCK_COUNT
36 #include "erl_lock_count.h"
37 #endif
38 
39 #include "erl_threads.h"
40 
41 #if defined(VALGRIND) || defined(ETHR_DISABLE_NATIVE_IMPLS)
42 #  define ERTS_PROC_LOCK_OWN_IMPL 0
43 #else
44 #  define ERTS_PROC_LOCK_OWN_IMPL 1
45 #endif
46 
47 #define ERTS_PROC_LOCK_ATOMIC_IMPL 0
48 #define ERTS_PROC_LOCK_SPINLOCK_IMPL 0
49 #define ERTS_PROC_LOCK_MUTEX_IMPL 0
50 
51 #if !ERTS_PROC_LOCK_OWN_IMPL
52 #define ERTS_PROC_LOCK_RAW_MUTEX_IMPL 1
53 #else
54 #define ERTS_PROC_LOCK_RAW_MUTEX_IMPL 0
55 
56 #if defined(ETHR_HAVE_32BIT_NATIVE_ATOMIC_OPS)
57 #  undef ERTS_PROC_LOCK_ATOMIC_IMPL
58 #  define ERTS_PROC_LOCK_ATOMIC_IMPL 1
59 #elif defined(ETHR_HAVE_NATIVE_SPINLOCKS)
60 #  undef ERTS_PROC_LOCK_SPINLOCK_IMPL
61 #  define ERTS_PROC_LOCK_SPINLOCK_IMPL 1
62 #else
63 #  undef ERTS_PROC_LOCK_MUTEX_IMPL
64 #  define ERTS_PROC_LOCK_MUTEX_IMPL 1
65 #endif
66 
67 #endif
68 
69 #define ERTS_PROC_LOCK_MAX_BIT 4
70 
71 typedef erts_aint32_t ErtsProcLocks;
72 
73 typedef struct erts_proc_lock_t_ {
74 #if ERTS_PROC_LOCK_OWN_IMPL
75 #if ERTS_PROC_LOCK_ATOMIC_IMPL
76     erts_atomic32_t flags;
77 #else
78     ErtsProcLocks flags;
79 #endif
80     erts_tse_t *queue[ERTS_PROC_LOCK_MAX_BIT+1];
81 #if defined(ERTS_ENABLE_LOCK_COUNT) && !ERTS_PROC_LOCK_RAW_MUTEX_IMPL
82     /* Each erts_mtx_t has its own lock counter ^ */
83 
84     #define ERTS_LCNT_PROCLOCK_IDX_MAIN 0
85     #define ERTS_LCNT_PROCLOCK_IDX_MSGQ 1
86     #define ERTS_LCNT_PROCLOCK_IDX_BTM 2
87     #define ERTS_LCNT_PROCLOCK_IDX_STATUS 3
88     #define ERTS_LCNT_PROCLOCK_IDX_TRACE 4
89 
90     #define ERTS_LCNT_PROCLOCK_COUNT 5
91 
92     erts_lcnt_ref_t lcnt_carrier;
93 #endif
94 #elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL
95     erts_mtx_t main;
96     erts_mtx_t msgq;
97     erts_mtx_t btm;
98     erts_mtx_t status;
99     erts_mtx_t trace;
100 #else
101 #  error "no implementation"
102 #endif
103 #ifdef ERTS_PROC_LOCK_DEBUG
104     erts_atomic32_t locked[ERTS_PROC_LOCK_MAX_BIT+1];
105 #endif
106 } erts_proc_lock_t;
107 
108 /* Process lock flags */
109 
110 /*
111  * Main lock:
112  *   The main lock is held by the scheduler running a process. It
113  *   is used to protect all fields in the process structure except
114  *   for those fields protected by other process locks (follows).
115  */
116 #define ERTS_PROC_LOCK_MAIN		(((ErtsProcLocks) 1) << 0)
117 
118 /*
119  * Message queue lock:
120  *   Protects the following fields in the process structure:
121  *   * msg_inq
122  */
123 #define ERTS_PROC_LOCK_MSGQ		(((ErtsProcLocks) 1) << 1)
124 
125 /*
126  * Bif timer lock:
127  *   Protects the following fields in the process structure:
128  *   * bif_timers
129  */
130 #define ERTS_PROC_LOCK_BTM		(((ErtsProcLocks) 1) << 2)
131 
132 /*
133  * Status lock:
134  *   Protects the following fields in the process structure:
135  *   * pending_suspenders
136  *   * suspendee
137  *   * sys_tasks
138  *   * ...
139  */
140 #define ERTS_PROC_LOCK_STATUS		(((ErtsProcLocks) 1) << 3)
141 
142 /*
143  * Trace message lock:
144  *   Protects the order in which messages are sent
145  *   from trace nifs. This lock is taken inside enif_send.
146  *
147  */
148 #define ERTS_PROC_LOCK_TRACE            (((ErtsProcLocks) 1) << ERTS_PROC_LOCK_MAX_BIT)
149 
150 /*
151  * Special fields:
152  *
153  *   The following fields are read only and can be read if at
154  *   least one process lock (whichever one doesn't matter)
155  *   is held, or if the process structure is guaranteed not to
156  *   disappear by other means (e.g. pix lock is held):
157  *     * id
158  *
159  *   The following fields are only allowed to be written if
160  *   all process locks are held, and are allowed to be read if
161  *   at least one process lock (whichever one doesn't matter)
162  *   is held:
163  *     * common.tracer
164  *     * common.trace_flags
165  *
166  *   The following fields are only allowed to be accessed if
167  *   both the schedule queue lock and at least one process lock
168  *   (whichever one doesn't matter) are held:
169  *     * prio
170  *     * next
171  *     * scheduler_flags
172  */
173 
174 /*
175  * Other rules regarding process locking:
176  *
177  * Exiting processes:
178  *   When changing state to exiting (ERTS_PSFLG_EXITING) on a process,
179  *   you are required to take all process locks (ERTS_PROC_LOCKS_ALL).
180  *   Thus, by holding at least one process lock (whichever one doesn't
181  *   matter) you are guaranteed that the process won't exit until the
182  *   lock you are holding has been released.
183  *
184  * Lock order:
185  *   Process locks with low numeric values has to be locked before
186  *   process locks with high numeric values. E.g., main locks has
187  *   to be locked before message queue locks.
188  *
189  *   When process locks with the same numeric value are to be locked
190  *   on multiple processes, locks on processes with low process ids
191  *   have to be locked before locks on processes with high process
192  *   ids. E.g., if the main and the message queue locks are to be
193  *   locked on processes p1 and p2 and p1->common.id < p2->common.id,
194  *   then locks should be locked in the following order:
195  *     1. main lock on p1
196  *     2. main lock on p2
197  *     3. message queue lock on p1
198  *     4. message queue lock on p2
199  */
200 
201 /* Other lock flags */
202 #define ERTS_PROC_LOCK_WAITER_SHIFT (ERTS_PROC_LOCK_MAX_BIT + 1)
203 
204 
205 /* ERTS_PROC_LOCKS_* are combinations of process locks */
206 
207 #define ERTS_PROC_LOCKS_MSG_RECEIVE	ERTS_PROC_LOCK_MSGQ
208 #define ERTS_PROC_LOCKS_MSG_SEND	ERTS_PROC_LOCK_MSGQ
209 #define ERTS_PROC_LOCKS_XSIG_SEND	ERTS_PROC_LOCK_STATUS
210 
211 #define ERTS_PROC_LOCKS_ALL \
212   ((((ErtsProcLocks) 1) << (ERTS_PROC_LOCK_MAX_BIT + 1)) - 1)
213 
214 #define ERTS_PROC_LOCKS_ALL_MINOR	(ERTS_PROC_LOCKS_ALL \
215                                          & ~ERTS_PROC_LOCK_MAIN)
216 
217 /* All locks we first must unlock to lock L */
218 #define ERTS_PROC_LOCKS_HIGHER_THAN(L) \
219   (ERTS_PROC_LOCKS_ALL & (~(L) & ~((L)-1)))
220 
221 
222 #define ERTS_PIX_LOCKS_BITS		10
223 #define ERTS_NO_OF_PIX_LOCKS		(1 << ERTS_PIX_LOCKS_BITS)
224 
225 
226 #endif /* #ifndef ERTS_PROC_LOCK_TYPE__ */
227 
228 #ifndef ERTS_PROCESS_LOCK_ONLY_PROC_LOCK_TYPE__
229 #ifndef ERTS_PROC_LOCK_LOCK_CHECK__
230 #define  ERTS_PROC_LOCK_LOCK_CHECK__
231 
232 /* Lock counter implemetation */
233 
234 #ifdef ERTS_ENABLE_LOCK_POSITION
235 #define erts_proc_lock__(P,I,L) erts_proc_lock_x__(P,I,L,__FILE__,__LINE__)
236 #define erts_proc_lock(P,L) erts_proc_lock_x(P,L,__FILE__,__LINE__)
237 #endif
238 
239 #if defined (ERTS_ENABLE_LOCK_COUNT)
240 
241 void erts_lcnt_proc_lock_init(Process *p);
242 void erts_lcnt_proc_lock_destroy(Process *p);
243 
244 ERTS_GLB_INLINE
245 void erts_lcnt_proc_lock(erts_proc_lock_t *lock, ErtsProcLocks locks);
246 ERTS_GLB_INLINE
247 void erts_lcnt_proc_lock_post_x(erts_proc_lock_t *lock, ErtsProcLocks locks, char *file, unsigned int line);
248 ERTS_GLB_INLINE
249 void erts_lcnt_proc_lock_unacquire(erts_proc_lock_t *lock, ErtsProcLocks locks);
250 ERTS_GLB_INLINE
251 void erts_lcnt_proc_unlock(erts_proc_lock_t *lock, ErtsProcLocks locks);
252 ERTS_GLB_INLINE
253 void erts_lcnt_proc_trylock(erts_proc_lock_t *lock, ErtsProcLocks locks, int res);
254 
255 void erts_lcnt_enable_proc_lock_count(Process *proc, int enable);
256 void erts_lcnt_update_process_locks(int enable);
257 
258 #if ERTS_GLB_INLINE_INCL_FUNC_DEF
259 
260 ERTS_GLB_INLINE
erts_lcnt_proc_lock(erts_proc_lock_t * lock,ErtsProcLocks locks)261 void erts_lcnt_proc_lock(erts_proc_lock_t *lock, ErtsProcLocks locks) {
262     erts_lcnt_lock_info_carrier_t *carrier;
263     int handle;
264 
265     if(erts_lcnt_open_ref(&lock->lcnt_carrier, &handle, &carrier)) {
266         if (locks & ERTS_PROC_LOCK_MAIN) {
267             erts_lcnt_lock_idx(carrier, ERTS_LCNT_PROCLOCK_IDX_MAIN);
268         }
269         if (locks & ERTS_PROC_LOCK_MSGQ) {
270             erts_lcnt_lock_idx(carrier, ERTS_LCNT_PROCLOCK_IDX_MSGQ);
271         }
272         if (locks & ERTS_PROC_LOCK_BTM) {
273             erts_lcnt_lock_idx(carrier, ERTS_LCNT_PROCLOCK_IDX_BTM);
274         }
275         if (locks & ERTS_PROC_LOCK_STATUS) {
276             erts_lcnt_lock_idx(carrier, ERTS_LCNT_PROCLOCK_IDX_STATUS);
277         }
278         if (locks & ERTS_PROC_LOCK_TRACE) {
279             erts_lcnt_lock_idx(carrier, ERTS_LCNT_PROCLOCK_IDX_TRACE);
280         }
281 
282         erts_lcnt_close_ref(handle, carrier);
283     }
284 }
285 
286 ERTS_GLB_INLINE
erts_lcnt_proc_lock_post_x(erts_proc_lock_t * lock,ErtsProcLocks locks,char * file,unsigned int line)287 void erts_lcnt_proc_lock_post_x(erts_proc_lock_t *lock, ErtsProcLocks locks,
288                                 char *file, unsigned int line) {
289     erts_lcnt_lock_info_carrier_t *carrier;
290     int handle;
291 
292     if(erts_lcnt_open_ref(&lock->lcnt_carrier, &handle, &carrier)) {
293         if (locks & ERTS_PROC_LOCK_MAIN) {
294             erts_lcnt_lock_post_x_idx(carrier, ERTS_LCNT_PROCLOCK_IDX_MAIN, file, line);
295         }
296         if (locks & ERTS_PROC_LOCK_MSGQ) {
297             erts_lcnt_lock_post_x_idx(carrier, ERTS_LCNT_PROCLOCK_IDX_MSGQ, file, line);
298         }
299         if (locks & ERTS_PROC_LOCK_BTM) {
300             erts_lcnt_lock_post_x_idx(carrier, ERTS_LCNT_PROCLOCK_IDX_BTM, file, line);
301         }
302         if (locks & ERTS_PROC_LOCK_STATUS) {
303             erts_lcnt_lock_post_x_idx(carrier, ERTS_LCNT_PROCLOCK_IDX_STATUS, file, line);
304         }
305         if (locks & ERTS_PROC_LOCK_TRACE) {
306             erts_lcnt_lock_post_x_idx(carrier, ERTS_LCNT_PROCLOCK_IDX_TRACE, file, line);
307         }
308 
309         erts_lcnt_close_ref(handle, carrier);
310     }
311 }
312 
313 ERTS_GLB_INLINE
erts_lcnt_proc_lock_unacquire(erts_proc_lock_t * lock,ErtsProcLocks locks)314 void erts_lcnt_proc_lock_unacquire(erts_proc_lock_t *lock, ErtsProcLocks locks) {
315     erts_lcnt_lock_info_carrier_t *carrier;
316     int handle;
317 
318     if(erts_lcnt_open_ref(&lock->lcnt_carrier, &handle, &carrier)) {
319         if (locks & ERTS_PROC_LOCK_MAIN) {
320             erts_lcnt_lock_unacquire_idx(carrier, ERTS_LCNT_PROCLOCK_IDX_MAIN);
321         }
322         if (locks & ERTS_PROC_LOCK_MSGQ) {
323             erts_lcnt_lock_unacquire_idx(carrier, ERTS_LCNT_PROCLOCK_IDX_MSGQ);
324         }
325         if (locks & ERTS_PROC_LOCK_BTM) {
326             erts_lcnt_lock_unacquire_idx(carrier, ERTS_LCNT_PROCLOCK_IDX_BTM);
327         }
328         if (locks & ERTS_PROC_LOCK_STATUS) {
329             erts_lcnt_lock_unacquire_idx(carrier, ERTS_LCNT_PROCLOCK_IDX_STATUS);
330         }
331         if (locks & ERTS_PROC_LOCK_TRACE) {
332             erts_lcnt_lock_unacquire_idx(carrier, ERTS_LCNT_PROCLOCK_IDX_TRACE);
333         }
334 
335         erts_lcnt_close_ref(handle, carrier);
336     }
337 }
338 
339 ERTS_GLB_INLINE
erts_lcnt_proc_unlock(erts_proc_lock_t * lock,ErtsProcLocks locks)340 void erts_lcnt_proc_unlock(erts_proc_lock_t *lock, ErtsProcLocks locks) {
341     erts_lcnt_lock_info_carrier_t *carrier;
342     int handle;
343 
344     if(erts_lcnt_open_ref(&lock->lcnt_carrier, &handle, &carrier)) {
345         if (locks & ERTS_PROC_LOCK_MAIN) {
346             erts_lcnt_unlock_idx(carrier, ERTS_LCNT_PROCLOCK_IDX_MAIN);
347         }
348         if (locks & ERTS_PROC_LOCK_MSGQ) {
349             erts_lcnt_unlock_idx(carrier, ERTS_LCNT_PROCLOCK_IDX_MSGQ);
350         }
351         if (locks & ERTS_PROC_LOCK_BTM) {
352             erts_lcnt_unlock_idx(carrier, ERTS_LCNT_PROCLOCK_IDX_BTM);
353         }
354         if (locks & ERTS_PROC_LOCK_STATUS) {
355             erts_lcnt_unlock_idx(carrier, ERTS_LCNT_PROCLOCK_IDX_STATUS);
356         }
357         if (locks & ERTS_PROC_LOCK_TRACE) {
358             erts_lcnt_unlock_idx(carrier, ERTS_LCNT_PROCLOCK_IDX_TRACE);
359         }
360 
361         erts_lcnt_close_ref(handle, carrier);
362     }
363 }
364 
365 ERTS_GLB_INLINE
erts_lcnt_proc_trylock(erts_proc_lock_t * lock,ErtsProcLocks locks,int res)366 void erts_lcnt_proc_trylock(erts_proc_lock_t *lock, ErtsProcLocks locks, int res) {
367     erts_lcnt_lock_info_carrier_t *carrier;
368     int handle;
369 
370     if(erts_lcnt_open_ref(&lock->lcnt_carrier, &handle, &carrier)) {
371         if (locks & ERTS_PROC_LOCK_MAIN) {
372             erts_lcnt_trylock_idx(carrier, ERTS_LCNT_PROCLOCK_IDX_MAIN, res);
373         }
374         if (locks & ERTS_PROC_LOCK_MSGQ) {
375             erts_lcnt_trylock_idx(carrier, ERTS_LCNT_PROCLOCK_IDX_MSGQ, res);
376         }
377         if (locks & ERTS_PROC_LOCK_BTM) {
378             erts_lcnt_trylock_idx(carrier, ERTS_LCNT_PROCLOCK_IDX_BTM, res);
379         }
380         if (locks & ERTS_PROC_LOCK_STATUS) {
381             erts_lcnt_trylock_idx(carrier, ERTS_LCNT_PROCLOCK_IDX_STATUS, res);
382         }
383         if (locks & ERTS_PROC_LOCK_TRACE) {
384             erts_lcnt_trylock_idx(carrier, ERTS_LCNT_PROCLOCK_IDX_TRACE, res);
385         }
386 
387         erts_lcnt_close_ref(handle, carrier);
388     }
389 } /* reversed logic */
390 
391 #endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */
392 #endif /* ERTS_ENABLE_LOCK_COUNT*/
393 
394 
395 
396 /* --- Process lock checking ----------------------------------------------- */
397 
398 #if defined(ERTS_ENABLE_LOCK_CHECK)
399 #define ERTS_CHK_NO_PROC_LOCKS \
400   erts_proc_lc_chk_no_proc_locks(__FILE__, __LINE__)
401 #define ERTS_CHK_HAVE_ONLY_MAIN_PROC_LOCK(P) \
402   erts_proc_lc_chk_only_proc_main((P))
403 void erts_proc_lc_lock(Process *p, ErtsProcLocks locks,
404 		       char *file, unsigned int line);
405 void erts_proc_lc_trylock(Process *p, ErtsProcLocks locks, int locked,
406 			  char *file, unsigned int line);
407 void erts_proc_lc_unlock(Process *p, ErtsProcLocks locks);
408 void erts_proc_lc_might_unlock(Process *p, ErtsProcLocks locks);
409 void erts_proc_lc_chk_have_proc_locks(Process *p, ErtsProcLocks locks);
410 void erts_proc_lc_chk_proc_locks(Process *p, ErtsProcLocks locks);
411 void erts_proc_lc_chk_only_proc_main(Process *p);
412 void erts_proc_lc_chk_only_proc(Process *p, ErtsProcLocks locks);
413 void erts_proc_lc_chk_no_proc_locks(char *file, int line);
414 ErtsProcLocks erts_proc_lc_my_proc_locks(Process *p);
415 int erts_proc_lc_trylock_force_busy(Process *p, ErtsProcLocks locks);
416 void erts_proc_lc_require_lock(Process *p, ErtsProcLocks locks,
417 			       char* file, unsigned int line);
418 void erts_proc_lc_unrequire_lock(Process *p, ErtsProcLocks locks);
419 #else
420 #define ERTS_CHK_NO_PROC_LOCKS
421 #define ERTS_CHK_HAVE_ONLY_MAIN_PROC_LOCK(P)
422 #endif
423 
424 #endif /* #ifndef ERTS_PROC_LOCK_LOCK_CHECK__ */
425 #endif /* #ifndef ERTS_PROCESS_LOCK_ONLY_PROC_LOCK_TYPE__ */
426 
427 #if !defined(ERTS_PROCESS_LOCK_ONLY_PROC_LOCK_TYPE__) \
428     && !defined(ERTS_PROCESS_LOCK_ONLY_LOCK_CHECK_PROTO__)
429 #ifndef ERTS_PROCESS_LOCK_H__
430 #define ERTS_PROCESS_LOCK_H__
431 
432 
433 typedef struct {
434     union {
435 	erts_mtx_t mtx;
436 	char buf[ERTS_ALC_CACHE_LINE_ALIGN_SIZE(sizeof(erts_mtx_t))];
437     } u;
438 } erts_pix_lock_t;
439 
440 #define ERTS_PID2PIXLOCK(PID) \
441     (&erts_pix_locks[(internal_pid_data((PID)) & ((1 << ERTS_PIX_LOCKS_BITS) - 1))])
442 
443 #if ERTS_PROC_LOCK_OWN_IMPL
444 
445 #if ERTS_PROC_LOCK_ATOMIC_IMPL
446 
447 #define ERTS_PROC_LOCK_FLGS_BAND_(L, MSK) \
448   ((ErtsProcLocks) erts_atomic32_read_band_nob(&(L)->flags, \
449 						   (erts_aint32_t) (MSK)))
450 #define ERTS_PROC_LOCK_FLGS_BOR_ACQB_(L, MSK) \
451   ((ErtsProcLocks) erts_atomic32_read_bor_acqb(&(L)->flags, \
452 						   (erts_aint32_t) (MSK)))
453 #define ERTS_PROC_LOCK_FLGS_CMPXCHG_ACQB_(L, NEW, EXPECTED) \
454   ((ErtsProcLocks) erts_atomic32_cmpxchg_acqb(&(L)->flags, \
455 						  (erts_aint32_t) (NEW), \
456 						  (erts_aint32_t) (EXPECTED)))
457 #define ERTS_PROC_LOCK_FLGS_CMPXCHG_RELB_(L, NEW, EXPECTED) \
458   ((ErtsProcLocks) erts_atomic32_cmpxchg_relb(&(L)->flags, \
459 						  (erts_aint32_t) (NEW), \
460 						  (erts_aint32_t) (EXPECTED)))
461 #define ERTS_PROC_LOCK_FLGS_READ_(L) \
462   ((ErtsProcLocks) erts_atomic32_read_nob(&(L)->flags))
463 
464 #else /* no opt atomic ops */
465 
466 ERTS_GLB_INLINE ErtsProcLocks erts_proc_lock_flags_band(erts_proc_lock_t *,
467 							ErtsProcLocks);
468 ERTS_GLB_INLINE ErtsProcLocks erts_proc_lock_flags_bor(erts_proc_lock_t *,
469 						       ErtsProcLocks);
470 ERTS_GLB_INLINE ErtsProcLocks erts_proc_lock_flags_cmpxchg(erts_proc_lock_t *,
471 							   ErtsProcLocks,
472 							   ErtsProcLocks);
473 
474 #if ERTS_GLB_INLINE_INCL_FUNC_DEF
475 
476 ERTS_GLB_INLINE ErtsProcLocks
erts_proc_lock_flags_band(erts_proc_lock_t * lck,ErtsProcLocks mask)477 erts_proc_lock_flags_band(erts_proc_lock_t *lck, ErtsProcLocks mask)
478 {
479     ErtsProcLocks res = lck->flags;
480     lck->flags &= mask;
481     return res;
482 }
483 
484 ERTS_GLB_INLINE ErtsProcLocks
erts_proc_lock_flags_bor(erts_proc_lock_t * lck,ErtsProcLocks mask)485 erts_proc_lock_flags_bor(erts_proc_lock_t *lck, ErtsProcLocks mask)
486 {
487     ErtsProcLocks res = lck->flags;
488     lck->flags |= mask;
489     return res;
490 }
491 
492 ERTS_GLB_INLINE ErtsProcLocks
erts_proc_lock_flags_cmpxchg(erts_proc_lock_t * lck,ErtsProcLocks new,ErtsProcLocks expected)493 erts_proc_lock_flags_cmpxchg(erts_proc_lock_t *lck, ErtsProcLocks new,
494                              ErtsProcLocks expected)
495 {
496     ErtsProcLocks res = lck->flags;
497     if (res == expected)
498         lck->flags = new;
499     return res;
500 }
501 
502 #endif
503 
504 #define ERTS_PROC_LOCK_FLGS_BAND_(L, MSK) erts_proc_lock_flags_band((L), (MSK))
505 #define ERTS_PROC_LOCK_FLGS_BOR_ACQB_(L, MSK) erts_proc_lock_flags_bor((L), (MSK))
506 #define ERTS_PROC_LOCK_FLGS_CMPXCHG_ACQB_(L, NEW, EXPECTED) \
507   erts_proc_lock_flags_cmpxchg((L), (NEW), (EXPECTED))
508 #define ERTS_PROC_LOCK_FLGS_CMPXCHG_RELB_(L, NEW, EXPECTED) \
509   erts_proc_lock_flags_cmpxchg((L), (NEW), (EXPECTED))
510 #define ERTS_PROC_LOCK_FLGS_READ_(L) ((L)->flags)
511 
512 #endif /* end no opt atomic ops */
513 #endif /* ERTS_PROC_LOCK_OWN_IMPL */
514 
515 extern erts_pix_lock_t erts_pix_locks[ERTS_NO_OF_PIX_LOCKS];
516 
517 void erts_init_proc_lock(int cpus);
518 void erts_proc_lock_prepare_proc_lock_waiter(void);
519 #if ERTS_PROC_LOCK_OWN_IMPL
520 void erts_proc_lock_failed(Process *,
521 			   erts_pix_lock_t *,
522 			   ErtsProcLocks,
523 			   ErtsProcLocks);
524 void erts_proc_unlock_failed(Process *,
525 			     erts_pix_lock_t *,
526 			     ErtsProcLocks);
527 #endif
528 
529 ERTS_GLB_INLINE void erts_pix_lock(erts_pix_lock_t *);
530 ERTS_GLB_INLINE void erts_pix_unlock(erts_pix_lock_t *);
531 ERTS_GLB_INLINE int erts_lc_pix_lock_is_locked(erts_pix_lock_t *);
532 
533 ERTS_GLB_INLINE ErtsProcLocks erts_proc_raw_trylock__(Process *p,
534 							  ErtsProcLocks locks);
535 #ifdef ERTS_ENABLE_LOCK_POSITION
536 ERTS_GLB_INLINE void erts_proc_lock_x__(Process *,
537 					    erts_pix_lock_t *,
538 					    ErtsProcLocks,
539 					    char *file, unsigned int line);
540 #else
541 ERTS_GLB_INLINE void erts_proc_lock__(Process *,
542 					  erts_pix_lock_t *,
543 					  ErtsProcLocks);
544 #endif
545 ERTS_GLB_INLINE void erts_proc_unlock__(Process *,
546 					    erts_pix_lock_t *,
547 					    ErtsProcLocks);
548 ERTS_GLB_INLINE int erts_proc_trylock__(Process *,
549 					    erts_pix_lock_t *,
550 					    ErtsProcLocks);
551 
552 #ifdef ERTS_PROC_LOCK_DEBUG
553 ERTS_GLB_INLINE void erts_proc_lock_op_debug(Process *, ErtsProcLocks, int);
554 #endif
555 
556 #if ERTS_GLB_INLINE_INCL_FUNC_DEF
557 
erts_pix_lock(erts_pix_lock_t * pixlck)558 ERTS_GLB_INLINE void erts_pix_lock(erts_pix_lock_t *pixlck)
559 {
560     ERTS_LC_ASSERT(pixlck);
561     erts_mtx_lock(&pixlck->u.mtx);
562 }
563 
erts_pix_unlock(erts_pix_lock_t * pixlck)564 ERTS_GLB_INLINE void erts_pix_unlock(erts_pix_lock_t *pixlck)
565 {
566     ERTS_LC_ASSERT(pixlck);
567     erts_mtx_unlock(&pixlck->u.mtx);
568 }
569 
erts_lc_pix_lock_is_locked(erts_pix_lock_t * pixlck)570 ERTS_GLB_INLINE int erts_lc_pix_lock_is_locked(erts_pix_lock_t *pixlck)
571 {
572     return erts_lc_mtx_is_locked(&pixlck->u.mtx);
573 }
574 
575 /*
576  * Helper function for erts_proc_lock__ and erts_proc_trylock__.
577  *
578  * Attempts to grab all of 'locks' simultaneously.
579  *
580  * On success, returns zero.
581  *
582  * On failure, returns the p->locks at the moment it tried to grab them,
583  * at least some of which will intersect with 'locks', so it is nonzero.
584  *
585  * This assumes p's pix lock is held on entry if !ERTS_PROC_LOCK_ATOMIC_IMPL.
586  * Does not release the pix lock.
587  */
588 ERTS_GLB_INLINE ErtsProcLocks
erts_proc_raw_trylock__(Process * p,ErtsProcLocks locks)589 erts_proc_raw_trylock__(Process *p, ErtsProcLocks locks)
590 {
591 #if ERTS_PROC_LOCK_OWN_IMPL
592     ErtsProcLocks expct_lflgs = 0;
593 
594     while (1) {
595         ErtsProcLocks lflgs = ERTS_PROC_LOCK_FLGS_CMPXCHG_ACQB_(&p->lock,
596 								expct_lflgs | locks,
597 								expct_lflgs);
598         if (ERTS_LIKELY(lflgs == expct_lflgs)) {
599             /* We successfully grabbed all locks. */
600             return 0;
601         }
602 
603         if (lflgs & locks) {
604             /* Some locks we need are locked, give up. */
605             return lflgs;
606         }
607 
608         /* cmpxchg failed, try again (should be rare). */
609         expct_lflgs = lflgs;
610     }
611 
612 #elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL
613 
614     if (locks & ERTS_PROC_LOCK_MAIN)
615 	if (erts_mtx_trylock(&p->lock.main) == EBUSY)
616 	    goto busy_main;
617     if (locks & ERTS_PROC_LOCK_MSGQ)
618 	if (erts_mtx_trylock(&p->lock.msgq) == EBUSY)
619 	    goto busy_msgq;
620     if (locks & ERTS_PROC_LOCK_BTM)
621 	if (erts_mtx_trylock(&p->lock.btm) == EBUSY)
622 	    goto busy_btm;
623     if (locks & ERTS_PROC_LOCK_STATUS)
624 	if (erts_mtx_trylock(&p->lock.status) == EBUSY)
625 	    goto busy_status;
626     if (locks & ERTS_PROC_LOCK_TRACE)
627 	if (erts_mtx_trylock(&p->lock.trace) == EBUSY)
628 	    goto busy_trace;
629 
630     return 0;
631 
632 busy_trace:
633     if (locks & ERTS_PROC_LOCK_TRACE)
634 	erts_mtx_unlock(&p->lock.trace);
635 busy_status:
636     if (locks & ERTS_PROC_LOCK_BTM)
637 	erts_mtx_unlock(&p->lock.btm);
638 busy_btm:
639     if (locks & ERTS_PROC_LOCK_MSGQ)
640 	erts_mtx_unlock(&p->lock.msgq);
641 busy_msgq:
642     if (locks & ERTS_PROC_LOCK_MAIN)
643 	erts_mtx_unlock(&p->lock.main);
644 busy_main:
645 
646     return EBUSY;
647 #endif
648 }
649 
650 ERTS_GLB_INLINE void
651 #ifdef ERTS_ENABLE_LOCK_POSITION
erts_proc_lock_x__(Process * p,erts_pix_lock_t * pix_lck,ErtsProcLocks locks,char * file,unsigned int line)652 erts_proc_lock_x__(Process *p,
653 		     erts_pix_lock_t *pix_lck,
654 		     ErtsProcLocks locks,
655 		     char *file, unsigned int line)
656 #else
657 erts_proc_lock__(Process *p,
658 		     erts_pix_lock_t *pix_lck,
659 		     ErtsProcLocks locks)
660 #endif
661 {
662 #if ERTS_PROC_LOCK_OWN_IMPL
663 
664     ErtsProcLocks old_lflgs;
665 #if !ERTS_PROC_LOCK_ATOMIC_IMPL
666     erts_pix_lock(pix_lck);
667 #endif
668 
669 #ifdef ERTS_ENABLE_LOCK_COUNT
670     erts_lcnt_proc_lock(&(p->lock), locks);
671 #endif
672 
673     ERTS_LC_ASSERT((locks & ~ERTS_PROC_LOCKS_ALL) == 0);
674 
675 #ifdef ERTS_ENABLE_LOCK_CHECK
676     erts_proc_lc_lock(p, locks, file, line);
677 #endif
678 
679     old_lflgs = erts_proc_raw_trylock__(p, locks);
680 
681     if (old_lflgs != 0) {
682 	/*
683          * There is lock contention, so let erts_proc_lock_failed() deal
684          * with it. Note that erts_proc_lock_failed() returns with
685          * pix_lck unlocked.
686          */
687 	erts_proc_lock_failed(p, pix_lck, locks, old_lflgs);
688     }
689 
690 #if !ERTS_PROC_LOCK_ATOMIC_IMPL
691     else {
692 	ERTS_LC_ASSERT(locks == (ERTS_PROC_LOCK_FLGS_READ_(&p->lock) & locks));
693 	erts_pix_unlock(pix_lck);
694     }
695 #endif
696 
697 #ifdef ERTS_ENABLE_LOCK_COUNT
698     erts_lcnt_proc_lock_post_x(&(p->lock), locks, file, line);
699 #endif
700 
701 #ifdef ERTS_PROC_LOCK_DEBUG
702     erts_proc_lock_op_debug(p, locks, 1);
703 #endif
704 
705 #if ERTS_PROC_LOCK_ATOMIC_IMPL
706     ETHR_COMPILER_BARRIER;
707 #endif
708 
709 #elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL
710     if (locks & ERTS_PROC_LOCK_MAIN)
711 	erts_mtx_lock(&p->lock.main);
712     if (locks & ERTS_PROC_LOCK_MSGQ)
713 	erts_mtx_lock(&p->lock.msgq);
714     if (locks & ERTS_PROC_LOCK_BTM)
715 	erts_mtx_lock(&p->lock.btm);
716     if (locks & ERTS_PROC_LOCK_STATUS)
717 	erts_mtx_lock(&p->lock.status);
718     if (locks & ERTS_PROC_LOCK_TRACE)
719 	erts_mtx_lock(&p->lock.trace);
720 
721 #ifdef ERTS_PROC_LOCK_DEBUG
722     erts_proc_lock_op_debug(p, locks, 1);
723 #endif
724 
725 #endif
726 }
727 
728 ERTS_GLB_INLINE void
erts_proc_unlock__(Process * p,erts_pix_lock_t * pix_lck,ErtsProcLocks locks)729 erts_proc_unlock__(Process *p,
730 		       erts_pix_lock_t *pix_lck,
731 		       ErtsProcLocks locks)
732 {
733 #if ERTS_PROC_LOCK_OWN_IMPL
734     ErtsProcLocks old_lflgs;
735 
736 #if ERTS_PROC_LOCK_ATOMIC_IMPL
737     ETHR_COMPILER_BARRIER;
738 #endif
739 
740 #ifdef ERTS_ENABLE_LOCK_COUNT
741     erts_lcnt_proc_unlock(&(p->lock), locks);
742 #endif
743 
744 #ifdef ERTS_ENABLE_LOCK_CHECK
745     erts_proc_lc_unlock(p, locks);
746 #endif
747 #ifdef ERTS_PROC_LOCK_DEBUG
748     erts_proc_lock_op_debug(p, locks, 0);
749 #endif
750 
751 #if !ERTS_PROC_LOCK_ATOMIC_IMPL
752     erts_pix_lock(pix_lck);
753 #endif
754 
755     old_lflgs = ERTS_PROC_LOCK_FLGS_READ_(&p->lock);
756 
757     ERTS_LC_ASSERT((locks & ~ERTS_PROC_LOCKS_ALL) == 0);
758     ERTS_LC_ASSERT(locks == (old_lflgs & locks));
759 
760     while (1) {
761         /*
762          * We'll atomically unlock every lock that has no waiter.
763          * If any locks with waiters remain we'll let
764          * erts_proc_unlock_failed() deal with them.
765          */
766         ErtsProcLocks wait_locks =
767             (old_lflgs >> ERTS_PROC_LOCK_WAITER_SHIFT) & locks;
768 
769         /* What p->lock will look like with all non-waited locks released. */
770         ErtsProcLocks want_lflgs = old_lflgs & (wait_locks | ~locks);
771 
772         if (want_lflgs != old_lflgs) {
773             ErtsProcLocks new_lflgs =
774                 ERTS_PROC_LOCK_FLGS_CMPXCHG_RELB_(&p->lock, want_lflgs, old_lflgs);
775 
776             if (new_lflgs != old_lflgs) {
777                 /* cmpxchg failed, try again. */
778                 old_lflgs = new_lflgs;
779                 continue;
780             }
781         }
782 
783         /* We have successfully unlocked every lock with no waiter. */
784 
785         if (want_lflgs & locks) {
786             /* Locks with waiters remain. */
787             /* erts_proc_unlock_failed() returns with pix_lck unlocked. */
788             erts_proc_unlock_failed(p, pix_lck, want_lflgs & locks);
789         }
790         else {
791 #if !ERTS_PROC_LOCK_ATOMIC_IMPL
792             erts_pix_unlock(pix_lck);
793 #endif
794         }
795 
796         break;
797     }
798 
799 #elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL
800 
801 #ifdef ERTS_PROC_LOCK_DEBUG
802     erts_proc_lock_op_debug(p, locks, 0);
803 #endif
804 
805     if (locks & ERTS_PROC_LOCK_TRACE)
806 	erts_mtx_unlock(&p->lock.trace);
807     if (locks & ERTS_PROC_LOCK_STATUS)
808 	erts_mtx_unlock(&p->lock.status);
809     if (locks & ERTS_PROC_LOCK_BTM)
810 	erts_mtx_unlock(&p->lock.btm);
811     if (locks & ERTS_PROC_LOCK_MSGQ)
812 	erts_mtx_unlock(&p->lock.msgq);
813     if (locks & ERTS_PROC_LOCK_MAIN)
814 	erts_mtx_unlock(&p->lock.main);
815 #endif
816 
817 }
818 
819 ERTS_GLB_INLINE int
erts_proc_trylock__(Process * p,erts_pix_lock_t * pix_lck,ErtsProcLocks locks)820 erts_proc_trylock__(Process *p,
821 			erts_pix_lock_t *pix_lck,
822 			ErtsProcLocks locks)
823 {
824 #if ERTS_PROC_LOCK_OWN_IMPL
825     int res;
826 
827 #ifdef ERTS_ENABLE_LOCK_CHECK
828     ERTS_LC_ASSERT((locks & ~ERTS_PROC_LOCKS_ALL) == 0);
829     if (erts_proc_lc_trylock_force_busy(p, locks)) {
830 	res = EBUSY; /* Make sure caller can handle the situation without
831 			causing a lock order violation to occur */
832     }
833     else
834 #endif
835     {
836 
837 #if !ERTS_PROC_LOCK_ATOMIC_IMPL
838 	erts_pix_lock(pix_lck);
839 #endif
840 
841 	if (erts_proc_raw_trylock__(p, locks) != 0) {
842 	    /* Didn't get all locks... */
843 	    res = EBUSY;
844 
845 #if !ERTS_PROC_LOCK_ATOMIC_IMPL
846 	    erts_pix_unlock(pix_lck);
847 #endif
848 	}
849 	else {
850 	    res = 0;
851 
852 	    ERTS_LC_ASSERT(locks
853 			   == (ERTS_PROC_LOCK_FLGS_READ_(&p->lock) & locks));
854 
855 #if !ERTS_PROC_LOCK_ATOMIC_IMPL
856 	    erts_pix_unlock(pix_lck);
857 #endif
858 
859 #ifdef ERTS_PROC_LOCK_DEBUG
860 	    erts_proc_lock_op_debug(p, locks, 1);
861 #endif
862 	}
863     }
864 #ifdef ERTS_ENABLE_LOCK_COUNT
865     erts_lcnt_proc_trylock(&(p->lock), locks, res);
866 #endif
867 
868 #ifdef ERTS_ENABLE_LOCK_CHECK
869     erts_proc_lc_trylock(p, locks, res == 0, __FILE__, __LINE__);
870 #endif
871 
872 #if ERTS_PROC_LOCK_ATOMIC_IMPL
873     ETHR_COMPILER_BARRIER;
874 #endif
875     return res;
876 
877 #elif ERTS_PROC_LOCK_RAW_MUTEX_IMPL
878     if (erts_proc_raw_trylock__(p, locks) != 0)
879 	return EBUSY;
880     else {
881 #ifdef ERTS_PROC_LOCK_DEBUG
882 	erts_proc_lock_op_debug(p, locks, 1);
883 #endif
884 	return 0;
885     }
886 #endif
887 }
888 
889 #ifdef ERTS_PROC_LOCK_DEBUG
890 ERTS_GLB_INLINE void
erts_proc_lock_op_debug(Process * p,ErtsProcLocks locks,int locked)891 erts_proc_lock_op_debug(Process *p, ErtsProcLocks locks, int locked)
892 {
893     int i;
894     for (i = 0; i <= ERTS_PROC_LOCK_MAX_BIT; i++) {
895 	ErtsProcLocks lock = ((ErtsProcLocks) 1) << i;
896 	if (locks & lock) {
897 	    erts_aint32_t lock_count;
898 	    if (locked) {
899 		lock_count = erts_atomic32_inc_read_nob(&p->lock.locked[i]);
900 		ERTS_LC_ASSERT(lock_count == 1);
901 	    }
902 	    else {
903 		lock_count = erts_atomic32_dec_read_nob(&p->lock.locked[i]);
904 		ERTS_LC_ASSERT(lock_count == 0);
905 	    }
906 	}
907     }
908 }
909 #endif
910 
911 #endif /* #if ERTS_GLB_INLINE_INCL_FUNC_DEF */
912 
913 
914 #ifdef ERTS_ENABLE_LOCK_POSITION
915 ERTS_GLB_INLINE void erts_proc_lock_x(Process *, ErtsProcLocks, char *file, unsigned int line);
916 #else
917 ERTS_GLB_INLINE void erts_proc_lock(Process *, ErtsProcLocks);
918 #endif
919 ERTS_GLB_INLINE void erts_proc_unlock(Process *, ErtsProcLocks);
920 ERTS_GLB_INLINE int erts_proc_trylock(Process *, ErtsProcLocks);
921 
922 ERTS_GLB_INLINE void erts_proc_inc_refc(Process *);
923 ERTS_GLB_INLINE void erts_proc_dec_refc(Process *);
924 ERTS_GLB_INLINE void erts_proc_dec_refc_free_func(Process *p,
925                                                   void (*func)(int, void *),
926                                                   void *arg);
927 ERTS_GLB_INLINE void erts_proc_add_refc(Process *, Sint);
928 ERTS_GLB_INLINE Sint erts_proc_read_refc(Process *);
929 
930 #if ERTS_GLB_INLINE_INCL_FUNC_DEF
931 
932 ERTS_GLB_INLINE void
933 #ifdef ERTS_ENABLE_LOCK_POSITION
erts_proc_lock_x(Process * p,ErtsProcLocks locks,char * file,unsigned int line)934 erts_proc_lock_x(Process *p, ErtsProcLocks locks, char *file, unsigned int line)
935 #else
936 erts_proc_lock(Process *p, ErtsProcLocks locks)
937 #endif
938 {
939 #if defined(ERTS_ENABLE_LOCK_POSITION)
940     erts_proc_lock_x__(p,
941 #if ERTS_PROC_LOCK_ATOMIC_IMPL
942 			 NULL,
943 #else
944 			 ERTS_PID2PIXLOCK(p->common.id),
945 #endif /*ERTS_PROC_LOCK_ATOMIC_IMPL*/
946 			 locks, file, line);
947 #else
948     erts_proc_lock__(p,
949 #if ERTS_PROC_LOCK_ATOMIC_IMPL
950 			 NULL,
951 #else
952 			 ERTS_PID2PIXLOCK(p->common.id),
953 #endif /*ERTS_PROC_LOCK_ATOMIC_IMPL*/
954 			 locks);
955 #endif /*ERTS_ENABLE_LOCK_POSITION*/
956 }
957 
958 ERTS_GLB_INLINE void
erts_proc_unlock(Process * p,ErtsProcLocks locks)959 erts_proc_unlock(Process *p, ErtsProcLocks locks)
960 {
961     erts_proc_unlock__(p,
962 #if ERTS_PROC_LOCK_ATOMIC_IMPL
963 			   NULL,
964 #else
965 			   ERTS_PID2PIXLOCK(p->common.id),
966 #endif
967 			   locks);
968 }
969 
970 ERTS_GLB_INLINE int
erts_proc_trylock(Process * p,ErtsProcLocks locks)971 erts_proc_trylock(Process *p, ErtsProcLocks locks)
972 {
973     return erts_proc_trylock__(p,
974 #if ERTS_PROC_LOCK_ATOMIC_IMPL
975 				   NULL,
976 #else
977 				   ERTS_PID2PIXLOCK(p->common.id),
978 #endif
979 				   locks);
980 }
981 
erts_proc_inc_refc(Process * p)982 ERTS_GLB_INLINE void erts_proc_inc_refc(Process *p)
983 {
984     ASSERT(!(erts_atomic32_read_nob(&p->state) & ERTS_PSFLG_PROXY));
985     erts_ptab_atmc_inc_refc(&p->common);
986 }
987 
erts_proc_dec_refc(Process * p)988 ERTS_GLB_INLINE void erts_proc_dec_refc(Process *p)
989 {
990     Sint referred;
991     ASSERT(!(erts_atomic32_read_nob(&p->state) & ERTS_PSFLG_PROXY));
992     referred = erts_ptab_atmc_dec_test_refc(&p->common);
993     if (!referred) {
994 	ASSERT(ERTS_PROC_IS_EXITING(p));
995 	erts_free_proc(p);
996     }
997 }
998 
erts_proc_dec_refc_free_func(Process * p,void (* func)(int,void *),void * arg)999 ERTS_GLB_INLINE void erts_proc_dec_refc_free_func(Process *p,
1000                                                   void (*func)(int, void *),
1001                                                   void *arg)
1002 {
1003     Sint referred;
1004     ASSERT(!(erts_atomic32_read_nob(&p->state) & ERTS_PSFLG_PROXY));
1005     referred = erts_ptab_atmc_dec_test_refc(&p->common);
1006     if (!referred) {
1007 	ASSERT(ERTS_PROC_IS_EXITING(p));
1008         (*func)(!0, arg);
1009 	erts_free_proc(p);
1010         (*func)(0, arg);
1011     }
1012 }
1013 
erts_proc_add_refc(Process * p,Sint add_refc)1014 ERTS_GLB_INLINE void erts_proc_add_refc(Process *p, Sint add_refc)
1015 {
1016     Sint referred;
1017     ASSERT(!(erts_atomic32_read_nob(&p->state) & ERTS_PSFLG_PROXY));
1018     referred = erts_ptab_atmc_add_test_refc(&p->common, add_refc);
1019     if (!referred) {
1020 	ASSERT(ERTS_PROC_IS_EXITING(p));
1021 	erts_free_proc(p);
1022     }
1023 }
1024 
erts_proc_read_refc(Process * p)1025 ERTS_GLB_INLINE Sint erts_proc_read_refc(Process *p)
1026 {
1027     ASSERT(!(erts_atomic32_read_nob(&p->state) & ERTS_PSFLG_PROXY));
1028     return erts_ptab_atmc_read_refc(&p->common);
1029 }
1030 
1031 #endif /* #if ERTS_GLB_INLINE_INCL_FUNC_DEF */
1032 
1033 void erts_proc_lock_init(Process *);
1034 void erts_proc_lock_fin(Process *);
1035 void erts_proc_safelock(Process *a_proc,
1036 			ErtsProcLocks a_have_locks,
1037 			ErtsProcLocks a_need_locks,
1038 			Process *b_proc,
1039 			ErtsProcLocks b_have_locks,
1040 			ErtsProcLocks b_need_locks);
1041 
1042 /*
1043  * --- Process table lookup ------------------------------------------------
1044  *
1045  * erts_pid2proc() and friends looks up the process structure of a pid
1046  * and at the same time acquires process locks in the smp case. Locks
1047  * on currently executing process and looked up process are taken according
1048  * to the lock order, i.e., locks on currently executing process may have
1049  * been released and reacquired.
1050  *
1051  * erts_pid2proc_opt() currently accepts the following flags:
1052  *   ERTS_P2P_FLG_ALLOW_OTHER_X    Lookup process even if it currently
1053  *                                 is exiting.
1054  */
1055 
1056 #define ERTS_P2P_FLG_ALLOW_OTHER_X	(1 <<  0)
1057 #define ERTS_P2P_FLG_TRY_LOCK		(1 <<  1)
1058 #define ERTS_P2P_FLG_INC_REFC		(1 <<  2)
1059 
1060 #define ERTS_PROC_LOCK_BUSY ((Process *) &erts_invalid_process)
1061 
1062 #define erts_pid2proc(PROC, HL, PID, NL) \
1063   erts_pid2proc_opt((PROC), (HL), (PID), (NL), 0)
1064 
1065 Process *erts_proc_lookup_inc_refc(Eterm pid);
1066 Process *erts_proc_lookup_raw_inc_refc(Eterm pid);
1067 
1068 ERTS_GLB_INLINE Process *erts_pix2proc(int ix);
1069 ERTS_GLB_INLINE Process *erts_proc_lookup_raw(Eterm pid);
1070 ERTS_GLB_INLINE Process *erts_proc_lookup(Eterm pid);
1071 
1072 Process *erts_pid2proc_opt(Process *, ErtsProcLocks, Eterm, ErtsProcLocks, int);
1073 
1074 #if ERTS_GLB_INLINE_INCL_FUNC_DEF
1075 
erts_pix2proc(int ix)1076 ERTS_GLB_INLINE Process *erts_pix2proc(int ix)
1077 {
1078     Process *proc;
1079     ASSERT(0 <= ix && ix < erts_ptab_max(&erts_proc));
1080     proc = (Process *) erts_ptab_pix2intptr_nob(&erts_proc, ix);
1081     return proc == ERTS_PROC_LOCK_BUSY ? NULL : proc;
1082 }
1083 
erts_proc_lookup_raw(Eterm pid)1084 ERTS_GLB_INLINE Process *erts_proc_lookup_raw(Eterm pid)
1085 {
1086     Process *proc;
1087 
1088     ERTS_LC_ASSERT(erts_thr_progress_lc_is_delaying());
1089 
1090     if (is_not_internal_pid(pid))
1091 	return NULL;
1092 
1093     proc = (Process *) erts_ptab_pix2intptr_ddrb(&erts_proc,
1094 						 internal_pid_index(pid));
1095     if (proc && proc->common.id != pid)
1096 	return NULL;
1097     return proc;
1098 }
1099 
erts_proc_lookup(Eterm pid)1100 ERTS_GLB_INLINE Process *erts_proc_lookup(Eterm pid)
1101 {
1102     Process *proc = erts_proc_lookup_raw(pid);
1103     if (proc && ERTS_PROC_IS_EXITING(proc))
1104 	return NULL;
1105     return proc;
1106 }
1107 
1108 
1109 #endif /* #if ERTS_GLB_INLINE_INCL_FUNC_DEF */
1110 
1111 #endif /* #ifndef ERTS_PROCESS_LOCK_H__ */
1112 #endif /* #if !defined(ERTS_PROCESS_LOCK_ONLY_PROC_LOCK_TYPE__)
1113 	  && !defined(ERTS_PROCESS_LOCK_ONLY_LOCK_CHECK_PROTO__) */
1114