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