summaryrefslogtreecommitdiff
path: root/src/common
diff options
context:
space:
mode:
Diffstat (limited to 'src/common')
-rw-r--r--src/common/bits.c38
1 files changed, 29 insertions, 9 deletions
diff --git a/src/common/bits.c b/src/common/bits.c
index 42493f2..2aa1be5 100644
--- a/src/common/bits.c
+++ b/src/common/bits.c
@@ -356,31 +356,51 @@ bool set_atomic_in_bit_field(bitfield_t *field, size_t first, size_t count)
size_t start; /* Mot de départ */
size_t end; /* Mot d'arrivée */
size_t remaining; /* Nombre de bits restants */
- unsigned long oldval; /* Ancienne valeur présente */
unsigned long mask; /* Nouvelle valeur à insérer */
+ unsigned long oldval; /* Ancienne valeur présente */
start = first / (sizeof(unsigned long) * 8);
end = (first + count - 1) / (sizeof(unsigned long) * 8);
-#if 0 //sizeof(gsize) != sizeof(unsigned long)
-# warning "Can not perform atomic operations on bit fields!"
-#else
if (start == end)
{
remaining = first % (sizeof(unsigned long) * 8);
- assert(count > 0);
+ assert(count > 0 && count <= (sizeof(unsigned long) * 8));
- mask = (1 << count) - 1;
- mask <<= remaining;
+ if (count == 64)
+ {
+ assert(remaining == 0);
+ mask = ~0lu;
+ }
+ else
+ {
+ mask = (1lu << count) - 1;
+ mask <<= remaining;
+ }
- oldval = g_atomic_pointer_or(&field->bits[start], mask);
+ /**
+ * Pour une raison inconnue, l'appel suivant est parfois sans effet :
+ *
+ * oldval = g_atomic_pointer_or(&field->bits[start], mask);
+ *
+ * On bascule donc dans l'équivalent plus long à exécuter...
+ */
+
+ g_mutex_lock(&field->mutex);
+
+ oldval = field->bits[start];
+
+ field->bits[start] |= mask;
+
+ g_mutex_unlock(&field->mutex);
result = ((oldval & mask) == 0);
+ assert(test_in_bit_field(field, first, count));
+
}
else
-#endif
{
g_mutex_lock(&field->mutex);