1
From 641103314a423328094624db0f518630d5d90dee Mon Sep 17 00:00:00 2001
2
From: David Henningsson <david.henningsson@canonical.com>
3
Date: Sun, 4 Mar 2012 06:07:37 +0100
4
Subject: [PATCH 1/2] flist: Avoid the ABA problem
6
Our flist implementation suffers from the ABA problem
7
(see http://en.wikipedia.org/wiki/ABA_problem), causing PulseAudio
8
to crash very rarely, usually inside memblock operations.
9
By turning stored pointers into stored table indices, we have some
10
extra bits that we can use to store tag bits, which is a known
11
workaround for the ABA problem.
13
Buglink: https://bugs.launchpad.net/bugs/924416
14
Signed-off-by: David Henningsson <david.henningsson@canonical.com>
16
src/pulsecore/flist.c | 70 ++++++++++++++++++++++++++++++++++--------------
17
1 files changed, 49 insertions(+), 21 deletions(-)
19
diff --git a/src/pulsecore/flist.c b/src/pulsecore/flist.c
20
index d279271..fa8974a 100644
21
--- a/src/pulsecore/flist.c
22
+++ b/src/pulsecore/flist.c
25
Copyright 2006-2008 Lennart Poettering
26
Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
27
+ Copyright (C) 2012 Canonical Ltd.
29
Contact: Jyri Sarha <Jyri.Sarha@nokia.com>
33
#define FLIST_SIZE 128
35
+/* Atomic table indices contain
36
+ sign bit = if set, indicates empty/NULL value
37
+ tag bits (to avoid the ABA problem)
41
/* Lock free single linked list element. */
42
struct pa_flist_elem {
43
- pa_atomic_ptr_t next;
48
@@ -49,34 +56,49 @@ typedef struct pa_flist_elem pa_flist_elem;
53
+ pa_atomic_t current_tag;
58
/* Stack that contains pointers stored into free list */
59
- pa_atomic_ptr_t stored;
61
/* Stack that contains empty list elements */
62
- pa_atomic_ptr_t empty;
64
pa_flist_elem table[];
67
/* Lock free pop from linked list stack */
68
-static pa_flist_elem *stack_pop(pa_atomic_ptr_t *list) {
69
- pa_flist_elem *poped;
70
+static pa_flist_elem *stack_pop(pa_flist *flist, pa_atomic_t *list) {
71
+ pa_flist_elem *popped;
76
- poped = (pa_flist_elem *) pa_atomic_ptr_load(list);
77
- } while (poped != NULL && !pa_atomic_ptr_cmpxchg(list, poped, pa_atomic_ptr_load(&poped->next)));
78
+ idx = pa_atomic_load(list);
81
+ popped = &flist->table[idx & flist->index_mask];
82
+ } while (!pa_atomic_cmpxchg(list, idx, pa_atomic_load(&popped->next)));
88
/* Lock free push to linked list stack */
89
-static void stack_push(pa_atomic_ptr_t *list, pa_flist_elem *new_elem) {
90
- pa_flist_elem *next;
91
+static void stack_push(pa_flist *flist, pa_atomic_t *list, pa_flist_elem *new_elem) {
92
+ int tag, newindex, next;
95
+ tag = pa_atomic_inc(&flist->current_tag);
96
+ newindex = new_elem - flist->table;
97
+ pa_assert(newindex >= 0 && newindex < (int) flist->size);
98
+ newindex |= (tag << flist->tag_shift) & flist->tag_mask;
101
- next = pa_atomic_ptr_load(list);
102
- pa_atomic_ptr_store(&new_elem->next, next);
103
- } while (!pa_atomic_ptr_cmpxchg(list, next, new_elem));
104
+ next = pa_atomic_load(list);
105
+ pa_atomic_store(&new_elem->next, next);
106
+ } while (!pa_atomic_cmpxchg(list, next, newindex));
109
pa_flist *pa_flist_new_with_name(unsigned size, const char *name) {
110
@@ -91,10 +113,16 @@ pa_flist *pa_flist_new_with_name(unsigned size, const char *name) {
112
l->name = pa_xstrdup(name);
114
- pa_atomic_ptr_store(&l->stored, NULL);
115
- pa_atomic_ptr_store(&l->empty, NULL);
117
+ while (1 << l->tag_shift < (int) size)
119
+ l->index_mask = (1 << l->tag_shift) - 1;
120
+ l->tag_mask = INT_MAX - l->index_mask;
122
+ pa_atomic_store(&l->stored, -1);
123
+ pa_atomic_store(&l->empty, -1);
124
for (i=0; i < size; i++) {
125
- stack_push(&l->empty, &l->table[i]);
126
+ stack_push(l, &l->empty, &l->table[i]);
130
@@ -109,7 +137,7 @@ void pa_flist_free(pa_flist *l, pa_free_cb_t free_cb) {
134
- while((elem = stack_pop(&l->stored)))
135
+ while((elem = stack_pop(l, &l->stored)))
136
free_cb(pa_atomic_ptr_load(&elem->ptr));
139
@@ -122,14 +150,14 @@ int pa_flist_push(pa_flist *l, void *p) {
143
- elem = stack_pop(&l->empty);
144
+ elem = stack_pop(l, &l->empty);
146
if (pa_log_ratelimit(PA_LOG_DEBUG))
147
pa_log_debug("%s flist is full (don't worry)", l->name);
150
pa_atomic_ptr_store(&elem->ptr, p);
151
- stack_push(&l->stored, elem);
152
+ stack_push(l, &l->stored, elem);
156
@@ -139,13 +167,13 @@ void* pa_flist_pop(pa_flist *l) {
160
- elem = stack_pop(&l->stored);
161
+ elem = stack_pop(l, &l->stored);
165
ptr = pa_atomic_ptr_load(&elem->ptr);
167
- stack_push(&l->empty, elem);
168
+ stack_push(l, &l->empty, elem);