aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam/code_ix.c
diff options
context:
space:
mode:
authorSverker Eriksson <[email protected]>2012-02-10 18:22:42 +0100
committerSverker Eriksson <[email protected]>2012-02-21 12:23:09 +0100
commitc4a8cc5914157c70ced742d957ec0e8d9c618164 (patch)
tree0ff4584ccb1d512b3fd48f596414f505d708c35f /erts/emulator/beam/code_ix.c
parent7da22e299ad0d2d6bf389650f4d74f4f22242111 (diff)
downloadotp-c4a8cc5914157c70ced742d957ec0e8d9c618164.tar.gz
otp-c4a8cc5914157c70ced742d957ec0e8d9c618164.tar.bz2
otp-c4a8cc5914157c70ced742d957ec0e8d9c618164.zip
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.
Diffstat (limited to 'erts/emulator/beam/code_ix.c')
-rw-r--r--erts/emulator/beam/code_ix.c57
1 files changed, 47 insertions, 10 deletions
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