Browse code

Allow lazy initialization of array and hashtable. Useful, when chances are good, that the data structure will remain empty. To get a lazy array or hashmap use size 0. Removed that extract function again, because I don't need it anymore.

Nat! authored on 11-04-2017 11:06:06
Showing 12 changed files
... ...
@@ -37,3 +37,5 @@ tests/hashmap/example
37 37
 tests/array/example.debug
38 38
 tests/hashmap/example.debug
39 39
 tests/hashmap/hashmap.debug
40
+tests/array/empty
41
+tests/array/empty.debug
40 42
\ No newline at end of file
... ...
@@ -1,4 +1,4 @@
1
-# mulle-concurrent
1
+_mulle_concurrent_hashmapstorage_lookup# mulle-concurrent
2 2
 
3 3
 **mulle-concurrent** is a library for lock- and wait-free data structures.
4 4
 Wait-freeness is a desirable property for "hotly" contested data structures
... ...
@@ -1,3 +1,9 @@
1
+1.3.1
2
+===
3
+
4
+* if you init a pointerarray or hashmap with size == 0, initialization will be 
5
+done lazily, using a static empty storage first.
6
+
1 7
 1.1.5
2 8
 ===
3 9
 
... ...
@@ -507,6 +507,7 @@
507 507
 			baseConfigurationReference = 417C02651BD8404E005A3751 /* Debug.xcconfig */;
508 508
 			buildSettings = {
509 509
 				CURRENT_PROJECT_VERSION = 0.5;
510
+				DEPENDENCIES_DIR = "$(PROJECT_DIR)/../dependencies";
510 511
 				GCC_WARN_PEDANTIC = YES;
511 512
 			};
512 513
 			name = Debug;
... ...
@@ -516,6 +517,7 @@
516 517
 			baseConfigurationReference = 417C02681BD8404E005A3751 /* Release.xcconfig */;
517 518
 			buildSettings = {
518 519
 				CURRENT_PROJECT_VERSION = 0.5;
520
+				DEPENDENCIES_DIR = "$(PROJECT_DIR)/../dependencies";
519 521
 				GCC_WARN_PEDANTIC = YES;
520 522
 			};
521 523
 			name = Release;
... ...
@@ -58,6 +58,18 @@ struct _mulle_concurrent_hashmapstorage
58 58
 };
59 59
 
60 60
 
61
+//
62
+// empty storage is designed, so that
63
+// you can make an optimistic read into entries
64
+//
65
+static const  struct _mulle_concurrent_hashmapstorage   empty_storage =
66
+{
67
+   (void *) -1,
68
+   0,
69
+   { { MULLE_CONCURRENT_NO_HASH, NULL } }
70
+};
71
+
72
+
61 73
 #define REDIRECT_VALUE     MULLE_CONCURRENT_INVALID_POINTER
62 74
 
63 75
 #pragma mark -
... ...
@@ -367,18 +379,16 @@ int  _mulle_concurrent_hashmap_init( struct mulle_concurrent_hashmap *map,
367 379
       allocator = &mulle_default_allocator;
368 380
 
369 381
    assert( allocator->abafree && allocator->abafree != (int (*)()) abort);
370
-   if( ! allocator->abafree || allocator->abafree == (int (*)()) abort)
371
-      return( EINVAL);
372 382
 
373 383
    map->allocator = allocator;
374
-   storage        = _mulle_concurrent_alloc_hashmapstorage( size, allocator);
375
-
376
-   if( ! storage)
377
-      return( ENOMEM);
384
+   if( size == 0)
385
+      storage = (void *) &empty_storage;
386
+   else
387
+      storage = _mulle_concurrent_alloc_hashmapstorage( size, allocator);
378 388
 
379 389
    _mulle_atomic_pointer_nonatomic_write( &map->storage.pointer, storage);
380 390
    _mulle_atomic_pointer_nonatomic_write( &map->next_storage.pointer, storage);
381
-
391
+   
382 392
    return( 0);
383 393
 }
384 394
 
... ...
@@ -395,8 +405,9 @@ void  _mulle_concurrent_hashmap_done( struct mulle_concurrent_hashmap *map)
395 405
    storage      = _mulle_atomic_pointer_nonatomic_read( &map->storage.pointer);
396 406
    next_storage = _mulle_atomic_pointer_nonatomic_read( &map->next_storage.pointer);
397 407
 
398
-   _mulle_allocator_abafree( map->allocator, storage);
399
-   if( storage != next_storage)
408
+   if( storage != &empty_storage)
409
+      _mulle_allocator_abafree( map->allocator, storage);
410
+   if( storage != next_storage && storage != &empty_storage)
400 411
       _mulle_allocator_abafree( map->allocator, next_storage);
401 412
 }
402 413
 
... ...
@@ -450,7 +461,7 @@ static int  _mulle_concurrent_hashmap_migrate_storage( struct mulle_concurrent_h
450 461
 
451 462
    // ok, if we succeed free old, if we fail alloced is
452 463
    // already gone. this must be an ABA free
453
-   if( previous == p)
464
+   if( previous == p && previous != &empty_storage)
454 465
       _mulle_allocator_abafree( map->allocator, previous); // ABA!!
455 466
 
456 467
    return( 0);
... ...
@@ -74,8 +74,8 @@ static inline int  mulle_concurrent_hashmap_init( struct mulle_concurrent_hashma
74 74
                                                   struct mulle_allocator *allocator)
75 75
 {
76 76
    int  _mulle_concurrent_hashmap_init( struct mulle_concurrent_hashmap *map,
77
-                                       unsigned int size,
78
-                                       struct mulle_allocator *allocator);
77
+                                        unsigned int size,
78
+                                        struct mulle_allocator *allocator);
79 79
    if( ! map)
80 80
       return( EINVAL);
81 81
    return( _mulle_concurrent_hashmap_init( map, size, allocator));
... ...
@@ -37,7 +37,7 @@
37 37
 //
38 38
 // community version is always even
39 39
 //
40
-#define MULLE_CONCURRENT_VERSION  ((1 << 20) | (1 << 8) | 5)
40
+#define MULLE_CONCURRENT_VERSION  ((1 << 20) | (3 << 8) | 1)
41 41
 
42 42
 #include <mulle_thread/mulle_thread.h>
43 43
 #include <mulle_allocator/mulle_allocator.h>
... ...
@@ -51,6 +51,8 @@ struct _mulle_concurrent_pointerarraystorage
51 51
 };
52 52
 
53 53
 
54
+static const struct _mulle_concurrent_pointerarraystorage   empty_storage;
55
+
54 56
 //
55 57
 // the nice thing about the redirect is, that another thread that is
56 58
 // trying to add at the same time cooperates
... ...
@@ -108,6 +110,24 @@ static void   *_mulle_concurrent_pointerarraystorage_get( struct _mulle_concurre
108 110
 }
109 111
 
110 112
 
113
+//static void   *_mulle_concurrent_pointerarraystorage_extract( struct _mulle_concurrent_pointerarraystorage *p,
114
+//                                                    unsigned int i)
115
+//{
116
+//   void   *value;
117
+//   
118
+//   do
119
+//   {
120
+//      assert( i < (unsigned int) (uintptr_t) _mulle_atomic_pointer_read( &p->n));
121
+//      value = _mulle_atomic_pointer_read( &p->entries[ i]);
122
+//      if( value == MULLE_CONCURRENT_NO_POINTER)
123
+//         break;
124
+//   }
125
+//   while( ! _mulle_atomic_pointer_compare_and_swap( &p->entries[ i], MULLE_CONCURRENT_NO_POINTER, value));
126
+//   
127
+//   return( value);
128
+//}
129
+
130
+
111 131
 //
112 132
 // insert:
113 133
 //
... ...
@@ -160,7 +180,8 @@ static void   _mulle_concurrent_pointerarraystorage_copy( struct _mulle_concurre
160 180
    for( i = n; p < p_last; p++, i++)
161 181
    {
162 182
       value = _mulle_atomic_pointer_read( p);
163
-      if( _mulle_atomic_pointer_compare_and_swap( &dst->entries[ i], value, MULLE_CONCURRENT_NO_POINTER))
183
+      // value == MULLE_CONCURRENT_NO_POINTER ? because of extract
184
+      if( value == MULLE_CONCURRENT_NO_POINTER || _mulle_atomic_pointer_compare_and_swap( &dst->entries[ i], value, MULLE_CONCURRENT_NO_POINTER))
164 185
          _mulle_atomic_pointer_increment( &dst->n);
165 186
    }
166 187
 }
... ...
@@ -181,7 +202,10 @@ void  _mulle_concurrent_pointerarray_init( struct mulle_concurrent_pointerarray
181 202
    assert( allocator->abafree && allocator->abafree != (int (*)()) abort);
182 203
 
183 204
    array->allocator = allocator;
184
-   storage          = _mulle_concurrent_alloc_pointerarraystorage( size, allocator);
205
+   if( size == 0)
206
+      storage = (void *) &empty_storage;
207
+   else
208
+      storage = _mulle_concurrent_alloc_pointerarraystorage( size, allocator);
185 209
 
186 210
    _mulle_atomic_pointer_nonatomic_write( &array->storage.pointer, storage);
187 211
    _mulle_atomic_pointer_nonatomic_write( &array->next_storage.pointer, storage);
... ...
@@ -199,8 +223,9 @@ void  _mulle_concurrent_pointerarray_done( struct mulle_concurrent_pointerarray
199 223
    storage      = _mulle_atomic_pointer_nonatomic_read( &array->storage.pointer);
200 224
    next_storage = _mulle_atomic_pointer_nonatomic_read( &array->next_storage.pointer);
201 225
 
202
-   _mulle_allocator_abafree( array->allocator, storage);
203
-   if( storage != next_storage)
226
+   if( storage != &empty_storage)
227
+      _mulle_allocator_abafree( array->allocator, storage);
228
+   if( storage != next_storage && storage != &empty_storage)
204 229
       _mulle_allocator_abafree( array->allocator, next_storage);
205 230
 }
206 231
 
... ...
@@ -269,7 +294,7 @@ static void  _mulle_concurrent_pointerarray_migrate_storage( struct mulle_concur
269 294
 
270 295
    // ok, if we succeed free old, if we fail alloced is
271 296
    // already gone
272
-   if( previous == p)
297
+   if( previous == p && previous != &empty_storage)
273 298
       _mulle_allocator_abafree( array->allocator, previous);
274 299
 }
275 300
 
... ...
@@ -292,6 +317,30 @@ retry:
292 317
 }
293 318
 
294 319
 
320
+//// hackish: replaces contents with NULL, returns previous value
321
+////          which could be NULL again
322
+////          not too sure about tj
323
+//void  *_mulle_concurrent_pointerarray_extract( struct mulle_concurrent_pointerarray *array,
324
+//                                               unsigned int index);
325
+//
326
+//void  *_mulle_concurrent_pointerarray_extract( struct mulle_concurrent_pointerarray *array,
327
+//                                               unsigned int index)
328
+//{
329
+//   struct _mulle_concurrent_pointerarraystorage   *p;
330
+//   void                                           *value;
331
+//
332
+//retry:
333
+//   p     = _mulle_atomic_pointer_read( &array->storage.pointer);
334
+//   value = _mulle_concurrent_pointerarraystorage_extract( p, index);
335
+//   if( value == REDIRECT_VALUE)
336
+//   {
337
+//      _mulle_concurrent_pointerarray_migrate_storage( array, p);
338
+//      goto retry;
339
+//   }
340
+//   return( value);
341
+//}
342
+
343
+
295 344
 void  _mulle_concurrent_pointerarray_add( struct mulle_concurrent_pointerarray *array,
296 345
                                          void *value)
297 346
 {
... ...
@@ -325,16 +374,6 @@ int  mulle_concurrent_pointerarray_add( struct mulle_concurrent_pointerarray *ar
325 374
 }
326 375
 
327 376
 
328
-void  *mulle_concurrent_pointerarray_get( struct mulle_concurrent_pointerarray *array,
329
-                                          unsigned int i)
330
-{
331
-   if( ! array)
332
-      return( NULL);
333
-   return( _mulle_concurrent_pointerarray_get( array, i));
334
-}
335
-
336
-
337
-
338 377
 int  mulle_concurrent_pointerarray_find( struct mulle_concurrent_pointerarray *array,
339 378
                                          void *value)
340 379
 {
... ...
@@ -121,8 +121,16 @@ static inline unsigned int  mulle_concurrent_pointerarray_get_count( struct mull
121 121
 int  mulle_concurrent_pointerarray_add( struct mulle_concurrent_pointerarray *array,
122 122
                                         void *value);
123 123
 
124
-void  *mulle_concurrent_pointerarray_get( struct mulle_concurrent_pointerarray *array,
125
-                                          unsigned int i);
124
+static inline void  *mulle_concurrent_pointerarray_get( struct mulle_concurrent_pointerarray *array,
125
+                                          unsigned int i)
126
+{
127
+   void  *_mulle_concurrent_pointerarray_get( struct mulle_concurrent_pointerarray *array,
128
+                                              unsigned int index);
129
+   if( ! array)
130
+      return( NULL);
131
+   return( _mulle_concurrent_pointerarray_get( array, i));
132
+}
133
+
126 134
 
127 135
 int  mulle_concurrent_pointerarray_find( struct mulle_concurrent_pointerarray *array,
128 136
                                          void *value);
129 137
new file mode 100644
... ...
@@ -0,0 +1,40 @@
1
+#include <mulle_concurrent/mulle_concurrent.h>
2
+
3
+#include <mulle_test_allocator/mulle_test_allocator.h>
4
+#include <mulle_aba/mulle_aba.h>
5
+#include <assert.h>
6
+#include <stdlib.h>
7
+#include <errno.h>
8
+
9
+
10
+static void   test( void)
11
+{
12
+   struct mulle_concurrent_pointerarray map;
13
+
14
+   mulle_concurrent_pointerarray_init( &map, 0, NULL);
15
+   printf( "%ld\n", _mulle_concurrent_pointerarray_get_size( &map));
16
+   printf( "%ld\n", _mulle_concurrent_pointerarray_get_count( &map));
17
+   printf( "%sfound\n",
18
+      _mulle_concurrent_pointerarray_find( &map, (void *) 0x1)
19
+           ? "" : "not ");
20
+   mulle_concurrent_pointerarray_done( &map);
21
+}
22
+
23
+
24
+int   main( void)
25
+{
26
+   mulle_test_allocator_initialize();
27
+   mulle_default_allocator = mulle_test_allocator;
28
+
29
+   mulle_aba_init( NULL);
30
+   mulle_aba_register();
31
+
32
+   test();
33
+
34
+   mulle_aba_unregister();
35
+   mulle_aba_done();
36
+
37
+   mulle_test_allocator_reset();
38
+
39
+   return( 0);
40
+}
0 41
new file mode 100644
... ...
@@ -0,0 +1,3 @@
1
+0
2
+0
3
+not found
... ...
@@ -1,4 +1,4 @@
1
-#! /bin/sh
1
+#! /usr/bin/env bash
2 2
 
3 3
 PROJECTDIR="`dirname "$PWD"`"
4 4
 PROJECTNAME="`basename "${PROJECTDIR}"`"