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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
|
/*
* %CopyrightBegin%
*
* Copyright Ericsson AB 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__
#ifndef __SYS_H__
# ifdef HAVE_CONFIG_H
# include "config.h"
# endif
# include "sys.h"
#endif
struct process;
#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 and the returned ix reused within the same BIF call.
*/
ERTS_GLB_INLINE
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.
*/
ERTS_GLB_INLINE
ErtsCodeIndex erts_staging_code_ix(void);
/* Try lock code_ix that is needed for (exlusive) access of the staging area.
* Main process lock (only) must be held.
* Caller is suspended and *must* yield if 0 is returned.
*/
int erts_try_lock_code_ix(struct process*);
/* Unlock code_ix
*/
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);
#ifdef ERTS_ENABLE_LOCK_CHECK
int erts_is_code_ix_locked(void);
#endif
#if ERTS_GLB_INLINE_INCL_FUNC_DEF
extern erts_smp_atomic32_t the_active_code_index;
extern erts_smp_atomic32_t the_staging_code_index;
ERTS_GLB_INLINE ErtsCodeIndex erts_active_code_ix(void)
{
return erts_smp_atomic32_read_nob(&the_active_code_index);
}
ERTS_GLB_INLINE ErtsCodeIndex erts_staging_code_ix(void)
{
return erts_smp_atomic32_read_nob(&the_staging_code_index);
}
#endif /* ERTS_GLB_INLINE_INCL_FUNC_DEF */
#endif /* !__CODE_IX_H__ */
|