aboutsummaryrefslogtreecommitdiffstats
path: root/erts/emulator/beam/erl_thr_queue.c
diff options
context:
space:
mode:
authorRickard Green <[email protected]>2011-12-07 20:05:39 +0100
committerRickard Green <[email protected]>2011-12-07 20:21:24 +0100
commit2bfc6d6791274e8f170e8972c899dcb66e8881c1 (patch)
treef6699766d360dd0cb9991886dab9c2206730a15f /erts/emulator/beam/erl_thr_queue.c
parent69969c2cd7b2aa3efbf35df8a908a17377a895a4 (diff)
downloadotp-2bfc6d6791274e8f170e8972c899dcb66e8881c1.tar.gz
otp-2bfc6d6791274e8f170e8972c899dcb66e8881c1.tar.bz2
otp-2bfc6d6791274e8f170e8972c899dcb66e8881c1.zip
Fix cleanup of elements in lock-free queues
Diffstat (limited to 'erts/emulator/beam/erl_thr_queue.c')
-rw-r--r--erts/emulator/beam/erl_thr_queue.c58
1 files changed, 38 insertions, 20 deletions
diff --git a/erts/emulator/beam/erl_thr_queue.c b/erts/emulator/beam/erl_thr_queue.c
index 9ac4cd4b8e..efb8c635d7 100644
--- a/erts/emulator/beam/erl_thr_queue.c
+++ b/erts/emulator/beam/erl_thr_queue.c
@@ -449,32 +449,44 @@ clean(ErtsThrQ_t *q, int max_ops, int do_notify)
if (inext == (erts_aint_t) &q->tail.data.marker) {
q->head.head.ptr->next.ptr = &q->tail.data.marker;
q->head.head.ptr = &q->tail.data.marker;
-#ifdef ERTS_SMP
- if (!q->head.next.thr_progress_reached)
- return ERTS_THR_Q_NEED_THR_PRGR;
-#else
- if (do_notify)
- q->head.notify(q->head.arg);
-#endif
- return ERTS_THR_Q_DIRTY;
+ goto check_thr_progress;
}
}
}
+
+ if (q->q.finalizing) {
+ ilast = erts_atomic_read_nob(&q->tail.data.last);
+ if (q->head.first == ((ErtsThrQElement_t *) ilast)
+ && ((ErtsThrQElement_t *) ilast) == &q->tail.data.marker
+ && q->head.first == &q->tail.data.marker) {
+ destroy(q);
+ }
+ else {
+ goto dirty;
+ }
+ }
return ERTS_THR_Q_CLEAN;
}
- if (q->head.first != q->head.unref_end) {
- if (do_notify)
- q->head.notify(q->head.arg);
- return ERTS_THR_Q_DIRTY;
- }
+ if (q->head.first != q->head.unref_end)
+ goto dirty;
+
+check_thr_progress:
#ifdef ERTS_SMP
- if (!q->head.next.thr_progress_reached)
- return ERTS_THR_Q_NEED_THR_PRGR;
+ if (q->head.next.thr_progress_reached)
#endif
+ {
+ int um_refc_ix = q->head.next.um_refc_ix;
+ if (erts_atomic_read_acqb(&q->tail.data.um_refc[um_refc_ix]) == 0) {
+ dirty:
+ if (do_notify)
+ q->head.notify(q->head.arg);
+ return ERTS_THR_Q_DIRTY;
+ }
+ }
- return ERTS_THR_Q_CLEAN; /* Waiting for unmanaged threads to complete... */
+ return ERTS_THR_Q_NEED_THR_PRGR;
}
#endif
@@ -492,7 +504,9 @@ erts_thr_q_clean(ErtsThrQ_t *q)
ErtsThrQCleanState_t
erts_thr_q_inspect(ErtsThrQ_t *q, int ensure_empty)
{
-#ifdef USE_THREADS
+#ifndef USE_THREADS
+ return ERTS_THR_Q_CLEAN;
+#else
if (ensure_empty) {
erts_aint_t inext;
inext = erts_atomic_read_acqb(&q->head.head.ptr->next.atmc);
@@ -523,11 +537,15 @@ erts_thr_q_inspect(ErtsThrQ_t *q, int ensure_empty)
return ERTS_THR_Q_DIRTY;
#ifdef ERTS_SMP
- if (!q->head.next.thr_progress_reached)
- return ERTS_THR_Q_NEED_THR_PRGR;
+ if (q->head.next.thr_progress_reached)
#endif
+ {
+ int um_refc_ix = q->head.next.um_refc_ix;
+ if (erts_atomic_read_acqb(&q->tail.data.um_refc[um_refc_ix]) == 0)
+ return ERTS_THR_Q_DIRTY;
+ }
+ return ERTS_THR_Q_NEED_THR_PRGR;
#endif
- return ERTS_THR_Q_CLEAN;
}
static void