aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam/code_ix.h
blob: f6926acab54d7490083772f5b8b0dfea6ddf7c9b (plain) (blame)
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__ */