1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
/*
* %CopyrightBegin%
*
* Copyright Ericsson AB 2012-2012. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
* compliance with the License. You should have received a copy of the
* Erlang Public License along with this software. If not, it can be
* retrieved online at http://www.erlang.org/.
*
* Software distributed under the License is distributed on an "AS IS"
* basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
* the License for the specific language governing rights and limitations
* under the License.
*
* %CopyrightEnd%
*/
/* Description:
* This is the interface that facilitate changing the beam code
* (load,upgrade,delete) while allowing executing Erlang processes to
* access the code without any locks or other expensive memory barriers.
*
* The basic idea is to maintain several "logical copies" of the code. These
* copies are identified by a global 'code index', an integer of 0, 1 or 2.
* The code index is used as argument to code access structures like
* export, module, beam_catches, beam_ranges.
*
* The current 'active' code index is used to access the current running
* code. The 'staging' code index is used by the process that performs
* a code change operation. When a code change operation completes
* succesfully, the staging code index becomes the new active code index.
*
* The third code index is not explicitly used. It can be thought of as
* the "previous active" or the "next staging" index. It is needed to make
* sure that we do not reuse a code index for staging until we are sure
* that no executing BIFs are still referring it.
* We could get by with only two (0 and 1), but that would require that we
* must wait for all schedulers to re-schedule before each code change
* operation can start staging.
*
* Note that the 'code index' is very loosely coupled to the concept of
* 'current' and 'old' module versions. You can almost say that they are
* orthogonal to each other. Code index is an emulator global concept while
* 'current' and 'old' is specific for each module.
*/
#ifndef __CODE_IX_H__
#define __CODE_IX_H__
#define ERTS_NUM_CODE_IX 3
typedef unsigned ErtsCodeIndex;
/* Called once at emulator initialization.
*/
void erts_code_ix_init(void);
/* Return active code index.
* Is guaranteed to be valid until the calling BIF returns.
* To get a consistent view of the code only one call to erts_active_code_ix()
* should be made within the same BIF call.
*/
ErtsCodeIndex erts_active_code_ix(void);
/* Return staging code ix.
* Only used by a process performing code loading/upgrading/deleting/purging.
* code_ix must be locked.
*/
ErtsCodeIndex erts_staging_code_ix(void);
/* Lock code_ix.
* Gives (exclusive) access to the staging area and write access to active code index.
* ToDo: Waiting process should be queued and return to be suspended.
*/
void erts_lock_code_ix(void);
/* Unlock code_ix
* ToDo: Dequeue and resume waiting processes.
*/
void erts_unlock_code_ix(void);
/* Make the "staging area" a complete copy of the active code.
* code_ix must be locked.
* Must be followed by a call to either "commit" or "abort" before code_ix lock
* is released.
*/
void erts_start_staging_code_ix(void);
/* Commit the staging area and update the active code index.
* code_ix must be locked and erts_start_staging_code_ix() called.
* ToDo: Updating active code index should be done according to Rickard's recipe.
* This function might need to be split into two.
*/
void erts_commit_staging_code_ix(void);
/* Abort the staging.
* code_ix must be locked and erts_start_staging_code_ix() called.
*/
void erts_abort_staging_code_ix(void);
void erts_rwlock_old_code(ErtsCodeIndex);
void erts_rwunlock_old_code(ErtsCodeIndex);
void erts_rlock_old_code(ErtsCodeIndex);
void erts_runlock_old_code(ErtsCodeIndex);
#ifdef ERTS_ENABLE_LOCK_CHECK
int erts_is_old_code_rlocked(ErtsCodeIndex);
int erts_is_code_ix_locked(void);
#endif
#endif /* !__CODE_IX_H__ */
|