From 7cb4725bcf18f3158e60750ea658e51ab4586e31 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 31 Jan 2012 14:24:40 +0100 Subject: erts: Refactor code_ix Move implementation from beam_load into new file code_ix.c and module.c and make some function inline. --- erts/emulator/beam/code_ix.c | 110 +++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 110 insertions(+) create mode 100644 erts/emulator/beam/code_ix.c (limited to 'erts/emulator/beam/code_ix.c') diff --git a/erts/emulator/beam/code_ix.c b/erts/emulator/beam/code_ix.c new file mode 100644 index 0000000000..a8b6599e61 --- /dev/null +++ b/erts/emulator/beam/code_ix.c @@ -0,0 +1,110 @@ +/* + * %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% + */ + +#ifdef HAVE_CONFIG_H +# include "config.h" +#endif + +#include "code_ix.h" +#include "global.h" +#include "beam_catches.h" + + + +#if 0 +# define CIX_TRACE(text) erts_fprintf(stderr, "CIX_TRACE: " text " act=%u load=%u\r\n", erts_active_code_ix(), erts_staging_code_ix()) +#else +# define CIX_TRACE(text) +#endif + +erts_smp_atomic32_t the_active_code_index; +erts_smp_atomic32_t the_staging_code_index; + +static erts_smp_mtx_t sverk_code_ix_lock; /*SVERK FIXME */ + +void erts_code_ix_init(void) +{ + /* We start emulator by initializing preloaded modules + * single threaded with active and staging set both to zero. + * Preloading is finished by a commit that will set things straight. + */ + erts_smp_atomic32_init_nob(&the_active_code_index, 0); + erts_smp_atomic32_init_nob(&the_staging_code_index, 0); + erts_smp_mtx_init_x(&sverk_code_ix_lock, "sverk_code_ix_lock", NIL); /*SVERK FIXME */ + CIX_TRACE("init"); +} + +void erts_start_staging_code_ix(void) +{ + beam_catches_start_staging(); + export_start_staging(); + module_start_staging(); + erts_start_staging_ranges(); + CIX_TRACE("start"); +} + + +void erts_commit_staging_code_ix(void) +{ + beam_catches_end_staging(1); + export_end_staging(1); + module_end_staging(1); + erts_end_staging_ranges(1); + { + ErtsCodeIndex ix; + export_write_lock(); + ix = erts_staging_code_ix(); + erts_smp_atomic32_set_nob(&the_active_code_index, ix); + ix = (ix + 1) % ERTS_NUM_CODE_IX; + erts_smp_atomic32_set_nob(&the_staging_code_index, ix); + export_write_unlock(); + } + CIX_TRACE("commit"); +} + +void erts_abort_staging_code_ix(void) +{ + beam_catches_end_staging(0); + export_end_staging(0); + module_end_staging(0); + erts_end_staging_ranges(0); + CIX_TRACE("abort"); +} + + +/* Lock code_ix (enqueue and suspend until we get it) +*/ +void erts_lock_code_ix(void) +{ + erts_smp_mtx_lock(&sverk_code_ix_lock); /*SVERK FIXME */ +} + +/* Unlock code_ix (resume first waiter) +*/ +void erts_unlock_code_ix(void) +{ + erts_smp_mtx_unlock(&sverk_code_ix_lock); /*SVERK FIXME */ +} + +#ifdef ERTS_ENABLE_LOCK_CHECK +int erts_is_code_ix_locked(void) +{ + return erts_smp_lc_mtx_is_locked(&sverk_code_ix_lock); +} +#endif -- cgit v1.2.3 From c4a8cc5914157c70ced742d957ec0e8d9c618164 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 10 Feb 2012 18:22:42 +0100 Subject: erts: Suspend processes waiting for code_ix lock This will prevent blocking entrire schedulers in the rare case when several processes are racing to load/upgrade/delete/purge code. --- erts/emulator/beam/code_ix.c | 57 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 10 deletions(-) (limited to 'erts/emulator/beam/code_ix.c') diff --git a/erts/emulator/beam/code_ix.c b/erts/emulator/beam/code_ix.c index a8b6599e61..a1db003127 100644 --- a/erts/emulator/beam/code_ix.c +++ b/erts/emulator/beam/code_ix.c @@ -36,7 +36,13 @@ erts_smp_atomic32_t the_active_code_index; erts_smp_atomic32_t the_staging_code_index; -static erts_smp_mtx_t sverk_code_ix_lock; /*SVERK FIXME */ +static int the_code_ix_lock = 0; +struct code_ix_queue_item { + Process *p; + struct code_ix_queue_item* next; +}; +static struct code_ix_queue_item* the_code_ix_queue = NULL; +static erts_smp_mtx_t the_code_ix_queue_lock; void erts_code_ix_init(void) { @@ -46,7 +52,7 @@ void erts_code_ix_init(void) */ erts_smp_atomic32_init_nob(&the_active_code_index, 0); erts_smp_atomic32_init_nob(&the_staging_code_index, 0); - erts_smp_mtx_init_x(&sverk_code_ix_lock, "sverk_code_ix_lock", NIL); /*SVERK FIXME */ + erts_smp_mtx_init(&the_code_ix_queue_lock, "code_ix_queue"); CIX_TRACE("init"); } @@ -88,23 +94,54 @@ void erts_abort_staging_code_ix(void) } -/* Lock code_ix (enqueue and suspend until we get it) -*/ -void erts_lock_code_ix(void) +/* Try lock code_ix + * Calller _must_ yield if we return 0 + */ +int erts_try_lock_code_ix(Process* c_p) { - erts_smp_mtx_lock(&sverk_code_ix_lock); /*SVERK FIXME */ + int success; + + erts_smp_mtx_lock(&the_code_ix_queue_lock); + success = !the_code_ix_lock; + if (success) { + the_code_ix_lock = 1; + } + else { /* Already locked */ + struct code_ix_queue_item* qitem; + qitem = erts_alloc(ERTS_ALC_T_CODE_IX_LOCK_Q, sizeof(*qitem)); + qitem->p = c_p; + erts_smp_proc_inc_refc(c_p); + qitem->next = the_code_ix_queue; + the_code_ix_queue = qitem; + erts_suspend(c_p, ERTS_PROC_LOCK_MAIN, NULL); + } + erts_smp_mtx_unlock(&the_code_ix_queue_lock); + return success; } -/* Unlock code_ix (resume first waiter) +/* Unlock code_ix (resume all waiters) */ -void erts_unlock_code_ix(void) +void erts_unlock_code_ix() { - erts_smp_mtx_unlock(&sverk_code_ix_lock); /*SVERK FIXME */ + erts_smp_mtx_lock(&the_code_ix_queue_lock); + while (the_code_ix_queue != NULL) { /* unleash the entire herd */ + struct code_ix_queue_item* qitem = the_code_ix_queue; + erts_smp_proc_lock(qitem->p, ERTS_PROC_LOCK_STATUS); + if (!ERTS_PROC_IS_EXITING(qitem->p)) { + erts_resume(qitem->p, ERTS_PROC_LOCK_STATUS); + } + erts_smp_proc_unlock(qitem->p, ERTS_PROC_LOCK_STATUS); + the_code_ix_queue = qitem->next; + erts_smp_proc_dec_refc(qitem->p); + erts_free(ERTS_ALC_T_CODE_IX_LOCK_Q, qitem); + } + the_code_ix_lock = 0; + erts_smp_mtx_unlock(&the_code_ix_queue_lock); } #ifdef ERTS_ENABLE_LOCK_CHECK int erts_is_code_ix_locked(void) { - return erts_smp_lc_mtx_is_locked(&sverk_code_ix_lock); + return the_code_ix_lock; } #endif -- cgit v1.2.3 From dc2b0ecba50cbe6b2f2321b1f24579a0353ced18 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 15 Feb 2012 15:12:18 +0100 Subject: erts: Activate staged code in a thread safe way Activation of staged code is scheduled for a later moment when all schedulers have done a full memory barrier. This allow them to read active code index while executing without any memory barriers at all. --- erts/emulator/beam/code_ix.c | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) (limited to 'erts/emulator/beam/code_ix.c') diff --git a/erts/emulator/beam/code_ix.c b/erts/emulator/beam/code_ix.c index a1db003127..5565b51e7e 100644 --- a/erts/emulator/beam/code_ix.c +++ b/erts/emulator/beam/code_ix.c @@ -66,22 +66,25 @@ void erts_start_staging_code_ix(void) } -void erts_commit_staging_code_ix(void) +void erts_end_staging_code_ix(void) { beam_catches_end_staging(1); export_end_staging(1); module_end_staging(1); erts_end_staging_ranges(1); - { - ErtsCodeIndex ix; - export_write_lock(); - ix = erts_staging_code_ix(); - erts_smp_atomic32_set_nob(&the_active_code_index, ix); - ix = (ix + 1) % ERTS_NUM_CODE_IX; - erts_smp_atomic32_set_nob(&the_staging_code_index, ix); - export_write_unlock(); - } - CIX_TRACE("commit"); + CIX_TRACE("end"); +} + +void erts_activate_staging_code_ix(void) +{ + ErtsCodeIndex ix; + export_write_lock(); + ix = erts_staging_code_ix(); + erts_smp_atomic32_set_nob(&the_active_code_index, ix); + ix = (ix + 1) % ERTS_NUM_CODE_IX; + erts_smp_atomic32_set_nob(&the_staging_code_index, ix); + export_write_unlock(); + CIX_TRACE("activate"); } void erts_abort_staging_code_ix(void) @@ -121,7 +124,7 @@ int erts_try_lock_code_ix(Process* c_p) /* Unlock code_ix (resume all waiters) */ -void erts_unlock_code_ix() +void erts_unlock_code_ix(void) { erts_smp_mtx_lock(&the_code_ix_queue_lock); while (the_code_ix_queue != NULL) { /* unleash the entire herd */ -- cgit v1.2.3 From cd63cd50bae6d98d6d56fa24674f14e7b9457a37 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Wed, 15 Feb 2012 17:08:47 +0100 Subject: erts: Refactor export staging lock Renamed it export_staging_lock and made change it to ordinary mutex. --- erts/emulator/beam/code_ix.c | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'erts/emulator/beam/code_ix.c') diff --git a/erts/emulator/beam/code_ix.c b/erts/emulator/beam/code_ix.c index 5565b51e7e..d4bf75558d 100644 --- a/erts/emulator/beam/code_ix.c +++ b/erts/emulator/beam/code_ix.c @@ -78,12 +78,13 @@ void erts_end_staging_code_ix(void) void erts_activate_staging_code_ix(void) { ErtsCodeIndex ix; - export_write_lock(); + /* We need to this lock as we are now making the staging export table active */ + export_staging_lock(); ix = erts_staging_code_ix(); erts_smp_atomic32_set_nob(&the_active_code_index, ix); ix = (ix + 1) % ERTS_NUM_CODE_IX; erts_smp_atomic32_set_nob(&the_staging_code_index, ix); - export_write_unlock(); + export_staging_unlock(); CIX_TRACE("activate"); } -- cgit v1.2.3 From 17c62a8d1158e2c13be403e62d81140c705a8444 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Tue, 21 Feb 2012 20:43:23 +0100 Subject: erts: Switch order between code_ix lock and thread blocking Make for simpler code when we just can block threads and continue without having to release code_ix lock and repeat code lookups to avoid race. --- erts/emulator/beam/code_ix.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'erts/emulator/beam/code_ix.c') diff --git a/erts/emulator/beam/code_ix.c b/erts/emulator/beam/code_ix.c index d4bf75558d..def7e164e2 100644 --- a/erts/emulator/beam/code_ix.c +++ b/erts/emulator/beam/code_ix.c @@ -105,6 +105,8 @@ int erts_try_lock_code_ix(Process* c_p) { int success; + ASSERT(!erts_smp_thr_progress_is_blocking()); + erts_smp_mtx_lock(&the_code_ix_queue_lock); success = !the_code_ix_lock; if (success) { -- cgit v1.2.3 From 62a41d25361de2ee08970a3905c63c503d3c89a1 Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Thu, 23 Feb 2012 12:13:31 +0100 Subject: erts: Refactor code loading with renaming Rename lock_code_ix as seize_code_write_permission. Don't want to call it a "lock" as it can be held between schedulings and different threads and is not managed by lock checker. Rename "activate" staging as "commit" staging. Why not be consistent and use git terminology all the way. --- erts/emulator/beam/code_ix.c | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) (limited to 'erts/emulator/beam/code_ix.c') diff --git a/erts/emulator/beam/code_ix.c b/erts/emulator/beam/code_ix.c index def7e164e2..9158d2d05c 100644 --- a/erts/emulator/beam/code_ix.c +++ b/erts/emulator/beam/code_ix.c @@ -75,7 +75,7 @@ void erts_end_staging_code_ix(void) CIX_TRACE("end"); } -void erts_activate_staging_code_ix(void) +void erts_commit_staging_code_ix(void) { ErtsCodeIndex ix; /* We need to this lock as we are now making the staging export table active */ @@ -98,14 +98,14 @@ void erts_abort_staging_code_ix(void) } -/* Try lock code_ix +/* * Calller _must_ yield if we return 0 */ -int erts_try_lock_code_ix(Process* c_p) +int erts_try_seize_code_write_permission(Process* c_p) { int success; - ASSERT(!erts_smp_thr_progress_is_blocking()); + ASSERT(!erts_smp_thr_progress_is_blocking()); /* to avoid deadlock */ erts_smp_mtx_lock(&the_code_ix_queue_lock); success = !the_code_ix_lock; @@ -125,9 +125,7 @@ int erts_try_lock_code_ix(Process* c_p) return success; } -/* Unlock code_ix (resume all waiters) -*/ -void erts_unlock_code_ix(void) +void erts_release_code_write_permission(void) { erts_smp_mtx_lock(&the_code_ix_queue_lock); while (the_code_ix_queue != NULL) { /* unleash the entire herd */ -- cgit v1.2.3 From 03ecf626b473e1c0015b1469e71403189f878ebc Mon Sep 17 00:00:00 2001 From: Sverker Eriksson Date: Fri, 24 Feb 2012 15:44:48 +0100 Subject: erts: Fix faulty assert in non-smp debug vm "is_blocking" always returns true on non-smp --- erts/emulator/beam/code_ix.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'erts/emulator/beam/code_ix.c') diff --git a/erts/emulator/beam/code_ix.c b/erts/emulator/beam/code_ix.c index 9158d2d05c..ae4cca1e58 100644 --- a/erts/emulator/beam/code_ix.c +++ b/erts/emulator/beam/code_ix.c @@ -104,8 +104,9 @@ void erts_abort_staging_code_ix(void) int erts_try_seize_code_write_permission(Process* c_p) { int success; - +#ifdef ERTS_SMP ASSERT(!erts_smp_thr_progress_is_blocking()); /* to avoid deadlock */ +#endif erts_smp_mtx_lock(&the_code_ix_queue_lock); success = !the_code_ix_lock; -- cgit v1.2.3