├── LICENSE ├── Makefile ├── main.c ├── wb_cas_pool.c ├── wb_cas_pool.h ├── wb_gcc.h ├── wb_object_pool.c ├── wb_object_pool.h ├── wb_pthread_pool.c ├── wb_pthread_pool.h ├── wb_spin_lock.h └── wb_spin_lock.inl /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 zerok 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | c_file =$(wildcard *.c) 2 | o_file =$(patsubst %.c,%.o,$(c_file)) 3 | d_file =$(patsubst %.c,%.d,$(c_file)) 4 | 5 | CURRENT_DIR :=$(shell pwd) 6 | CC = gcc 7 | CC_FLAGS = -g -O2 -fPIC -I/usr/local/include 8 | LD_FLAGS = -lpthread 9 | CC_DEPFLAGS =-MMD -MF $(@:.o=.d) -MT $@ 10 | 11 | 12 | 13 | all: print_c print_o obj_pool 14 | 15 | print_c: 16 | echo $(c_file) 17 | print_o: 18 | echo $(o_file) 19 | 20 | %.o: %.c 21 | $(CC) $(CC_FLAGS) $(CC_DEPFLAGS) -c $< -o $@ 22 | 23 | obj_pool: $(o_file) 24 | gcc -o obj_pool $(o_file) $(LD_FLAGS) 25 | 26 | 27 | .PHONY :clean 28 | 29 | clean: 30 | rm -f $(o_file) $(d_file) obj_pool 31 | 32 | 33 | -include $(wildcard $(FILE_O:.o=.d)) 34 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "wb_gcc.h" 9 | #include "wb_pthread_pool.h" 10 | #include "wb_object_pool.h" 11 | #include "wb_cas_pool.h" 12 | 13 | static char pad1[CACHE_LINE_ALIGNMENT]; 14 | static cell_pool_t* obj_pool = NULL; 15 | static char pad2[CACHE_LINE_ALIGNMENT]; 16 | static cas_pool_t* cas_pool = NULL; 17 | static char pad3[CACHE_LINE_ALIGNMENT]; 18 | static mutex_pool_t* mutex_pool = NULL; 19 | static char pad4[CACHE_LINE_ALIGNMENT]; 20 | 21 | 22 | #define TMAGIC 0x0395ef09 23 | 24 | typedef struct{ 25 | int index; 26 | uint32_t magic; 27 | }tobject_t; 28 | 29 | int32_t obj_init(void* ptr) 30 | { 31 | return 0; 32 | } 33 | 34 | void obj_destroy(void* ptr) 35 | { 36 | } 37 | 38 | void obj_reset(void* ptr, int32_t flag) 39 | { 40 | tobject_t* obj = (tobject_t *)ptr; 41 | obj->magic = (flag == 1 ? TMAGIC : 0); 42 | } 43 | 44 | int32_t obj_check(void* ptr) 45 | { 46 | tobject_t* obj = (tobject_t *)ptr; 47 | if (obj->magic == TMAGIC) 48 | return 0; 49 | 50 | assert(0); 51 | return -1; 52 | } 53 | 54 | #define THREAD_NUM 4 55 | #define POWER 3 56 | #define POOL_SIZE (1 << POWER) 57 | 58 | static int32_t alloc_count = 0; 59 | 60 | static void* thread_mutex_func(void* arg) 61 | { 62 | tobject_t* arr[POOL_SIZE / 2] = { 0 }; 63 | int i = 0; 64 | int l = 0; 65 | while (alloc_count < 1000000){ 66 | arr[i] = (tobject_t *)mutex_pool_alloc(mutex_pool); 67 | arr[i]->index = arr[i]->index + 1; 68 | i++; 69 | if (i >= POOL_SIZE / 2){ 70 | for (l = 0; l < i; l++){ 71 | mutex_pool_free(mutex_pool, arr[l]); 72 | } 73 | i = 0; 74 | } 75 | 76 | WT_ATOMIC_ADD4(alloc_count, 1); 77 | } 78 | 79 | if (i >= 0) 80 | for (l = 0; l < i; l++) 81 | mutex_pool_free(mutex_pool, arr[l]); 82 | 83 | return NULL; 84 | } 85 | 86 | static void* thread_spin_func(void* arg) 87 | { 88 | tobject_t* arr[POOL_SIZE / 2] = {0}; 89 | int i = 0; 90 | int l = 0; 91 | while (alloc_count < 1000000){ 92 | arr[i] = (tobject_t *)pool_alloc(obj_pool); 93 | arr[i]->index = arr[i]->index + 1; 94 | i++; 95 | if (i >= POOL_SIZE / 2){ 96 | for (l = 0; l < i; l++){ 97 | pool_free(obj_pool, arr[l]); 98 | } 99 | i = 0; 100 | } 101 | 102 | WT_ATOMIC_ADD4(alloc_count, 1); 103 | } 104 | 105 | if (i > 0) 106 | for (l = 0; l < i; l++){ 107 | pool_free(obj_pool, arr[l]); 108 | } 109 | 110 | return NULL; 111 | } 112 | 113 | static void* thread_cas_func(void* arg) 114 | { 115 | tobject_t* obj = NULL; 116 | int i = 0; 117 | int l = 0; 118 | while (alloc_count < 1000000){ 119 | obj = (tobject_t *)cas_pool_alloc(cas_pool); 120 | obj->index++; 121 | 122 | cas_pool_free(cas_pool, obj); 123 | 124 | WT_ATOMIC_ADD4(alloc_count, 1); 125 | } 126 | 127 | 128 | return NULL; 129 | } 130 | 131 | void test_mutex_pool() 132 | { 133 | pthread_t threads[THREAD_NUM]; 134 | tobject_t* o = NULL; 135 | tobject_t* ar[POOL_SIZE]; 136 | int i = 0; 137 | struct timeval b, e; 138 | 139 | mutex_pool = mutex_pool_create("pthread_mutex", sizeof(tobject_t), POOL_SIZE, obj_init, obj_destroy, obj_check, obj_reset); 140 | 141 | for (i = 0; i < POOL_SIZE; i++){ 142 | o = (tobject_t *)mutex_pool_alloc(mutex_pool); 143 | printf("alloc obj = 0x%lx\n", (uint64_t)o); 144 | ar[i] = o; 145 | } 146 | 147 | for (i = 0; i < POOL_SIZE; i++){ 148 | mutex_pool_free(mutex_pool, ar[i]); 149 | } 150 | 151 | o = (tobject_t *)mutex_pool_alloc(mutex_pool); 152 | printf("only o = 0x%lx\n", (uint64_t)o); 153 | mutex_pool_free(mutex_pool, o); 154 | 155 | gettimeofday(&b, NULL); 156 | for (i = 0; i < THREAD_NUM; i++) 157 | pthread_create(&threads[i], NULL, thread_mutex_func, NULL); 158 | 159 | for (i = 0; i < THREAD_NUM; i++) 160 | pthread_join(threads[i], NULL); 161 | 162 | gettimeofday(&e, NULL); 163 | printf("mutex alloc_count = %d, delay = %lu ms\n", alloc_count, ((e.tv_sec - b.tv_sec) * 1000000 + (e.tv_usec - b.tv_usec)) / 1000); 164 | 165 | mutex_pool_print(mutex_pool); 166 | 167 | mutex_pool_destroy(mutex_pool); 168 | } 169 | 170 | void test_spin_pool() 171 | { 172 | pthread_t threads[THREAD_NUM]; 173 | tobject_t* o = NULL; 174 | tobject_t* ar[POOL_SIZE]; 175 | int i = 0; 176 | struct timeval b, e; 177 | 178 | obj_pool = pool_create("spin", sizeof(tobject_t), POOL_SIZE, obj_init, obj_destroy, obj_check, obj_reset); 179 | 180 | for (i = 0; i < POOL_SIZE; i++){ 181 | o = (tobject_t *)pool_alloc(obj_pool); 182 | printf("alloc obj = 0x%lx\n", (uint64_t)o); 183 | ar[i] = o; 184 | } 185 | 186 | for (i = 0; i < POOL_SIZE; i++){ 187 | pool_free(obj_pool, ar[i]); 188 | } 189 | 190 | o = (tobject_t *)pool_alloc(obj_pool); 191 | printf("only o = 0x%lx\n", (uint64_t)o); 192 | pool_free(obj_pool, o); 193 | 194 | gettimeofday(&b, NULL); 195 | for (i = 0; i < THREAD_NUM; i++) 196 | pthread_create(&threads[i], NULL, thread_spin_func, NULL); 197 | 198 | for (i = 0; i < THREAD_NUM; i++) 199 | pthread_join(threads[i], NULL); 200 | 201 | gettimeofday(&e, NULL); 202 | printf("spin alloc_count = %d, delay = %lu ms\n", alloc_count, ((e.tv_sec - b.tv_sec) * 1000000 + (e.tv_usec - b.tv_usec)) / 1000); 203 | 204 | pool_print(obj_pool); 205 | 206 | pool_destroy(obj_pool); 207 | } 208 | 209 | void test_cas_pool() 210 | { 211 | pthread_t threads[THREAD_NUM]; 212 | tobject_t* o = NULL; 213 | tobject_t* ar[POOL_SIZE]; 214 | int i = 0; 215 | struct timeval b, e; 216 | 217 | cas_pool = cas_pool_create("cas", sizeof(tobject_t), obj_init, obj_destroy, obj_check, obj_reset); 218 | 219 | for (i = 0; i < POOL_SIZE; i++){ 220 | o = (tobject_t *)cas_pool_alloc(cas_pool); 221 | printf("alloc obj = 0x%lx\n", (uint64_t)o); 222 | ar[i] = o; 223 | } 224 | 225 | for (i = 0; i < POOL_SIZE; i++){ 226 | cas_pool_free(cas_pool, ar[i]); 227 | } 228 | 229 | o = (tobject_t *)cas_pool_alloc(cas_pool); 230 | printf("only o = 0x%lx\n", (uint64_t)o); 231 | 232 | cas_pool_print(cas_pool); 233 | cas_pool_free(cas_pool, o); 234 | 235 | gettimeofday(&b, NULL); 236 | for (i = 0; i < THREAD_NUM; i++) 237 | pthread_create(&threads[i], NULL, thread_cas_func, NULL); 238 | 239 | for (i = 0; i < THREAD_NUM; i++) 240 | pthread_join(threads[i], NULL); 241 | 242 | gettimeofday(&e, NULL); 243 | printf("cas alloc_count = %d, delay = %lu ms\n", alloc_count, ((e.tv_sec - b.tv_sec) * 1000000 + (e.tv_usec - b.tv_usec)) / 1000); 244 | 245 | cas_pool_print(cas_pool); 246 | 247 | cas_pool_destroy(cas_pool); 248 | } 249 | 250 | int main(int argc, const char* argv[]) 251 | { 252 | test_mutex_pool(); 253 | 254 | alloc_count = 0; 255 | test_spin_pool(); 256 | 257 | alloc_count = 0; 258 | 259 | test_cas_pool(); 260 | 261 | return 0; 262 | } 263 | 264 | 265 | 266 | -------------------------------------------------------------------------------- /wb_cas_pool.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | #include "wb_cas_pool.h" 8 | 9 | #define HEAD_PTR(ptr) (((char*)(ptr)) - sizeof(cas_object_t)) 10 | #define OBJ_PTR(head) (char*)((head)->ptr) 11 | 12 | #define CAS_MAGIC 0x9875ef6d 13 | 14 | /* idea from go's compiler core */ 15 | static inline uint64_t cas_obj_pack(cas_object_t* ob) 16 | { 17 | return (((uint64_t)ob) << 16) | (ob->index & ((1 << 16) - 1)); 18 | } 19 | 20 | static inline cas_object_t* cas_obj_unpack(uint64_t node) 21 | { 22 | return (cas_object_t*)(node >> 16); 23 | } 24 | 25 | /* call this function when program init! */ 26 | cas_pool_t* cas_pool_create(const char* name, size_t ob_size, cas_constructor_t constructor, cas_destructor_t destructor, 27 | cas_check_t check, cas_reset_t reset) 28 | { 29 | cas_pool_t* pool = (cas_pool_t *)calloc(1, sizeof(cas_pool_t)); 30 | char* nm = strdup(name); 31 | if (nm == NULL || pool == NULL){ 32 | free(nm); 33 | free(pool); 34 | return NULL; 35 | } 36 | 37 | pool->name = nm; 38 | pool->ob_size = ob_size; 39 | pool->constructor = constructor; 40 | pool->destructor = destructor; 41 | pool->check = check; 42 | pool->reset = reset; 43 | 44 | return pool; 45 | } 46 | 47 | /* call this function before program destroy */ 48 | void cas_pool_destroy(cas_pool_t* pool) 49 | { 50 | uint64_t node, next; 51 | cas_object_t* ob; 52 | while (pool->header != 0){ 53 | ob = cas_obj_unpack(pool->header); 54 | 55 | next = ob->next; 56 | pool->destructor(OBJ_PTR(ob)); 57 | free(ob); 58 | 59 | pool->header = next; 60 | } 61 | 62 | free(pool->name); 63 | free(pool); 64 | } 65 | 66 | static inline void* cas_alloc() 67 | { 68 | cas_object_t* obj = (cas_object_t* )malloc(sizeof(cas_object_t)); 69 | obj->magic = CAS_MAGIC; 70 | obj->next = 0; 71 | obj->index = 0; 72 | 73 | return OBJ_PTR(obj); 74 | } 75 | 76 | void* cas_pool_alloc(cas_pool_t* pool) 77 | { 78 | void* ptr; 79 | cas_object_t* ob; 80 | uint64_t node, next; 81 | 82 | do{ 83 | node = pool->header; 84 | WT_READ_BARRIER(); 85 | 86 | if (node == 0){ 87 | ptr = cas_alloc(); 88 | pool->constructor(ptr); 89 | 90 | goto exit_lapel; 91 | } 92 | 93 | /* ptr + node->index */ 94 | ob = cas_obj_unpack(node); 95 | next = ob->next; 96 | } while (!__WT_ATOMIC_CAS(pool->header, node, next, sizeof(uint64_t))); 97 | 98 | ptr = OBJ_PTR(ob); 99 | WT_ATOMIC_SUB4(pool->pool_size, 1); 100 | 101 | exit_lapel: 102 | pool->reset(ptr, 1); 103 | 104 | return ptr; 105 | } 106 | 107 | void cas_pool_free(cas_pool_t* pool, void* ptr) 108 | { 109 | uint64_t old, node; 110 | cas_object_t* ob = HEAD_PTR(ptr); 111 | 112 | if (ob->magic != CAS_MAGIC || pool->check(ptr) != 0){ 113 | assert(0); 114 | return; 115 | } 116 | 117 | pool->reset(ptr, 0); 118 | 119 | /* generate global node! double-CAS */ 120 | ++ob->index; 121 | node = cas_obj_pack(ob); 122 | 123 | do{ 124 | old = pool->header; 125 | WT_READ_BARRIER(); 126 | 127 | ob->next = old; 128 | } while (!__WT_ATOMIC_CAS(pool->header, old, node, sizeof(uint64_t))); 129 | 130 | WT_ATOMIC_ADD4(pool->pool_size, 1); 131 | } 132 | 133 | void cas_pool_print(cas_pool_t* pool) 134 | { 135 | if (pool == NULL){ 136 | printf("cas pool's ptr = NULL!"); 137 | return; 138 | } 139 | 140 | printf("cas pool:\n"); 141 | printf("\t name = %s\n\tob size = %d\n\tarray size = %d\n", pool->name, (int)pool->ob_size, pool->pool_size); 142 | } 143 | 144 | int32_t cas_get_pool_info(cas_pool_t* pool, char* buf) 145 | { 146 | int32_t pos = 0; 147 | assert(pool != NULL); 148 | 149 | pos = sprintf(buf, "%s pool:\n", pool->name); 150 | pos += sprintf(buf + pos, "\tob size = %d\n\tarray size = %d\n", (int)pool->ob_size, pool->pool_size); 151 | 152 | return pos; 153 | } -------------------------------------------------------------------------------- /wb_cas_pool.h: -------------------------------------------------------------------------------- 1 | #ifndef __WB_CAS_POOL_H_ 2 | #define __WB_CAS_POOL_H_ 3 | 4 | #include 5 | #include 6 | 7 | #include "wb_gcc.h" 8 | 9 | typedef int32_t(*cas_constructor_t)(void* ob); 10 | typedef void(*cas_destructor_t)(void* ob); 11 | typedef int32_t(*cas_check_t)(void* ob); 12 | typedef void(*cas_reset_t)(void* ob, int32_t flag); 13 | 14 | typedef struct cas_object_t 15 | { 16 | uint64_t next; 17 | uint32_t magic; 18 | uint32_t index; 19 | char ptr[]; 20 | }cas_object_t; 21 | 22 | typedef struct CACHE_ALIGN cas_pool_t 23 | { 24 | uint64_t header; 25 | int32_t pool_size; 26 | 27 | size_t ob_size; 28 | 29 | cas_constructor_t constructor; 30 | cas_destructor_t destructor; 31 | cas_check_t check; 32 | cas_reset_t reset; 33 | 34 | char* name; /*pool name*/ 35 | }cas_pool_t; 36 | 37 | cas_pool_t* cas_pool_create(const char* name, size_t ob_size, cas_constructor_t constructor, cas_destructor_t destructor, 38 | cas_check_t check, cas_reset_t reset); 39 | 40 | void cas_pool_destroy(cas_pool_t* pool); 41 | void* cas_pool_alloc(cas_pool_t* pool); 42 | void cas_pool_free(cas_pool_t* pool, void* ptr); 43 | 44 | void cas_pool_print(cas_pool_t* pool); 45 | int32_t cas_get_pool_info(cas_pool_t* pool, char* buf); 46 | 47 | #endif 48 | 49 | 50 | 51 | -------------------------------------------------------------------------------- /wb_gcc.h: -------------------------------------------------------------------------------- 1 | 2 | #define WT_STATIC_ASSERT(cond) (void)sizeof(char[1 - 2 * !(cond)]) 3 | 4 | #define WT_SIZET_FMT "zu" 5 | 6 | 7 | #define WT_COMPILER_TYPE_ALIGN(x) __attribute__((align(x))) 8 | 9 | #define WT_PACKED_STRUCT_BEGIN(name) struct __attribute__ ((__packed__)) name { 10 | #define WT_PACKED_STRUCT_END } 11 | 12 | #define WT_GCC_FUNC_ATTRIBUTE(x) 13 | #define WT_GCC_FUNC_DECL_ATTRIBUTE(x) __attribute__(x) 14 | 15 | #define __WT_ATOMIC_ADD(v, val, n) (WT_STATIC_ASSERT(sizeof(v) == (n)), __sync_add_and_fetch(&(v), val)) 16 | #define __WT_ATOMIC_FETCH_ADD(v, val, n) (WT_STATIC_ASSERT(sizeof(v) == (n)), __sync_fetch_and_add(&(v), val)) 17 | #define __WT_ATOMIC_CAS(v, old, ne, n) (WT_STATIC_ASSERT(sizeof(v) == (n)), __sync_val_compare_and_swap(&(v), old, ne) == (old)) 18 | #define __WT_ATOMIC_CAS_VAL(v, old, ne, n) (WT_STATIC_ASSERT(sizeof(v) == (n)), __sync_val_compare_and_swap(&(v), old, ne)) 19 | #define __WT_ATOMIC_STORE(v, val, n) (WT_STATIC_ASSERT(sizeof(v) == (n)), __sync_lock_test_and_set(&(v), val)) 20 | 21 | #define __WT_ATOMIC_SUB(v, val, n) (WT_STATIC_ASSERT(sizeof(v) == (n)), __sync_sub_and_fetch(&(v), val)) 22 | 23 | /*int8_t*/ 24 | #define WT_ATOMIC_ADD1(v, val) __WT_ATOMIC_ADD(v, val, 1) 25 | #define WT_ATOMIC_FETCH_ADD1(v, val) __WT_ATOMIC_FETCH_ADD(v, val, 1) 26 | #define WT_ATOMIC_CAS1(v, old, ne) __WT_ATOMIC_CAS(v, old, ne, 1) 27 | #define WT_ATOMIC_CAS_VAL1(v, old, ne) __WT_ATOMIC_CAS_VAL(v, old, ne, 1) 28 | #define WT_ATOMIC_STORE1(v, val) __WT_ATOMIC_STORE(v, val, 1) 29 | #define WT_ATOMIC_SUB1(v, val) __WT_ATOMIC_SUB(v, val, 1) 30 | 31 | /*int16_t*/ 32 | #define WT_ATOMIC_ADD2(v, val) __WT_ATOMIC_ADD(v, val, 2) 33 | #define WT_ATOMIC_FETCH_ADD2(v, val) __WT_ATOMIC_FETCH_ADD(v, val, 2) 34 | #define WT_ATOMIC_CAS2(v, old, ne) __WT_ATOMIC_CAS(v, old, ne, 2) 35 | #define WT_ATOMIC_CAS_VAL2(v, old, ne) __WT_ATOMIC_CAS_VAL(v, old, ne, 2) 36 | #define WT_ATOMIC_STORE2(v, val) __WT_ATOMIC_STORE(v, val, 2) 37 | #define WT_ATOMIC_SUB2(v, val) __WT_ATOMIC_SUB(v, val, 2) 38 | 39 | /*int32_t*/ 40 | #define WT_ATOMIC_ADD4(v, val) __WT_ATOMIC_ADD(v, val, 4) 41 | #define WT_ATOMIC_FETCH_ADD4(v, val) __WT_ATOMIC_FETCH_ADD(v, val, 4) 42 | #define WT_ATOMIC_CAS4(v, old, ne) __WT_ATOMIC_CAS(v, old, ne, 4) 43 | #define WT_ATOMIC_CAS_VAL4(v, old, ne) __WT_ATOMIC_CAS_VAL(v, old, ne, 4) 44 | #define WT_ATOMIC_STORE4(v, val) __WT_ATOMIC_STORE(v, val, 4) 45 | #define WT_ATOMIC_SUB4(v, val) __WT_ATOMIC_SUB(v, val, 4) 46 | 47 | /*int64_t*/ 48 | #define WT_ATOMIC_ADD8(v, val) __WT_ATOMIC_ADD(v, val, 8) 49 | #define WT_ATOMIC_FETCH_ADD8(v, val) __WT_ATOMIC_FETCH_ADD(v, val, 8) 50 | #define WT_ATOMIC_CAS8(v, old, ne) __WT_ATOMIC_CAS(v, old, ne, 8) 51 | #define WT_ATOMIC_CAS_VAL8(v, old, ne) __WT_ATOMIC_CAS_VAL(v, old, ne, 8) 52 | #define WT_ATOMIC_STORE8(v, val) __WT_ATOMIC_STORE(v, val, 8) 53 | #define WT_ATOMIC_SUB8(v, val) __WT_ATOMIC_SUB(v, val, 8) 54 | 55 | #ifdef SU_SERVER 56 | #define WT_BARRIER() __asm__ volatile("" ::: "memory") 57 | #define WT_PAUSE() __asm__ volatile("pause\n" ::: "memory") 58 | 59 | #if defined(x86_64) || defined(__x86_64__) 60 | #define WT_FULL_BARRIER() do{ __asm__ volatile("mfence" ::: "memory");}while(0) 61 | #define WT_READ_BARRIER() do{ __asm__ volatile("lfence" ::: "memory");}while(0) 62 | #define WT_WRITE_BARRIER() do{ __asm__ volatile("sfence" ::: "memory");}while(0) 63 | #elif defined(i386) || defined(__i386__) 64 | #define WT_FULL_BARRIER() do{__asm__ volatile ("lock; addl $0, 0(%%esp)" ::: "memory");}while(0) 65 | #define WT_READ_BARRIER() WT_FULL_BARRIER() 66 | #define WT_WRITE_BARRIER() WT_FULL_BARRIER() 67 | #else 68 | #error "No write barrier implementation for this hardware" 69 | #endif 70 | #else 71 | #define WT_BARRIER() 72 | #define WT_PAUSE() 73 | #define WT_FULL_BARRIER() 74 | #define WT_READ_BARRIER() 75 | #define WT_WRITE_BARRIER() 76 | #endif 77 | 78 | #define CACHE_LINE_ALIGNMENT 64 79 | 80 | #define CACHE_ALIGN __attribute__((aligned(CACHE_LINE_ALIGNMENT))) 81 | 82 | /**********************************************************************************************/ 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /wb_object_pool.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "wb_object_pool.h" 9 | 10 | cell_pool_t* pool_create(const char* name, size_t ob_size, size_t array_size, 11 | ob_constructor_t constructor, ob_destructor_t destructor, ob_check_t check, ob_reset_t reset) 12 | { 13 | cell_pool_t* pool = (cell_pool_t *)calloc(1, sizeof(cell_pool_t)); 14 | char* nm = strdup(name); 15 | void** ptr = (void **)calloc(1, sizeof(void*)* array_size); 16 | if(ptr == NULL || nm == NULL || pool == NULL){ 17 | free(ptr); 18 | free(nm); 19 | free(pool); 20 | 21 | return NULL; 22 | } 23 | 24 | pool->name = nm; 25 | pool->ptr = ptr; 26 | pool->array_size = array_size; 27 | pool->ob_size = ob_size; 28 | 29 | pool->constructor = constructor; 30 | pool->destructor = destructor; 31 | pool->check = check; 32 | pool->reset = reset; 33 | 34 | lock_init(&(pool->mutex)); 35 | 36 | return pool; 37 | } 38 | 39 | void pool_destroy(cell_pool_t* pool) 40 | { 41 | lock_destroy(&(pool->mutex)); 42 | 43 | while(pool->curr > 0){ 44 | void* ptr = pool->ptr[--pool->curr]; 45 | if(pool->destructor) 46 | pool->destructor(ptr); 47 | 48 | free(ptr); 49 | } 50 | 51 | free(pool->name); 52 | free(pool->ptr); 53 | free(pool); 54 | } 55 | 56 | void* pool_alloc(cell_pool_t* pool) 57 | { 58 | void* ret; 59 | 60 | lock_clock(&(pool->mutex), 64); 61 | 62 | if(pool->curr > 0){ 63 | ret = pool->ptr[--pool->curr]; 64 | lock_unlock(&(pool->mutex)); 65 | } 66 | else{ 67 | lock_unlock(&(pool->mutex)); 68 | 69 | ret = malloc(pool->ob_size); 70 | if(ret != NULL && pool->constructor(ret) != 0){ 71 | free(ret); 72 | ret = NULL; 73 | } 74 | } 75 | 76 | if(ret != NULL) 77 | pool->reset(ret, 1); 78 | 79 | return ret; 80 | } 81 | 82 | void pool_free(cell_pool_t* pool, void* ob) 83 | { 84 | if(ob == NULL && pool->check(ob) != 0){ 85 | return ; 86 | } 87 | 88 | pool->reset(ob, 0); 89 | 90 | lock_clock(&(pool->mutex), 64); 91 | 92 | if(pool->curr < pool->array_size){ 93 | pool->ptr[pool->curr ++] = ob; 94 | lock_unlock(&(pool->mutex)); 95 | } 96 | else{ 97 | size_t new_size = 2 * pool->array_size; 98 | void** new_ptr = (void**)realloc(pool->ptr, sizeof(void *) * new_size); 99 | if(new_ptr != NULL){ 100 | pool->array_size = new_size; 101 | pool->ptr = new_ptr; 102 | pool->ptr[pool->curr ++] = ob; 103 | 104 | lock_unlock(&(pool->mutex)); 105 | } 106 | else{ 107 | lock_unlock(&(pool->mutex)); 108 | 109 | pool->destructor(ob); 110 | free(ob); 111 | } 112 | } 113 | } 114 | 115 | void pool_print(cell_pool_t* pool) 116 | { 117 | if(pool == NULL){ 118 | printf("cell pool's ptr = NULL!"); 119 | return; 120 | } 121 | printf("cell pool:\n"); 122 | printf("\t name = %s\n\tob size = %d\n\tarray size = %d\n\tcurr = %d\n", 123 | pool->name, (int)pool->ob_size, pool->array_size, pool->curr); 124 | } 125 | 126 | int32_t get_pool_info(cell_pool_t* pool, char* buf) 127 | { 128 | int32_t pos = 0; 129 | assert(pool != NULL); 130 | 131 | lock_lock(&(pool->mutex)); 132 | 133 | pos = sprintf(buf, "%s pool:\n", pool->name); 134 | pos += sprintf(buf + pos, "\tob size = %d\n\tarray size = %d\n\tcurr = %d\n", (int)pool->ob_size, pool->array_size, pool->curr); 135 | 136 | lock_unlock(&(pool->mutex)); 137 | 138 | return pos; 139 | } 140 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /wb_object_pool.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuanrongxi/lock-free-object-pool/1a9359b9f51a7b749a515480a99b2be31f8bf518/wb_object_pool.h -------------------------------------------------------------------------------- /wb_pthread_pool.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | #include "wb_pthread_pool.h" 9 | 10 | mutex_pool_t* mutex_pool_create(const char* name, size_t ob_size, size_t array_size, 11 | mutex_constructor_t constructor, mutex_destructor_t destructor, mutex_check_t check, mutex_reset_t reset) 12 | { 13 | mutex_pool_t* pool = (mutex_pool_t *)calloc(1, sizeof(mutex_pool_t)); 14 | char* nm = strdup(name); 15 | void** ptr = (void **)calloc(1, sizeof(void*)* array_size); 16 | if (ptr == NULL || nm == NULL || pool == NULL){ 17 | free(ptr); 18 | free(nm); 19 | free(pool); 20 | 21 | return NULL; 22 | } 23 | 24 | pool->name = nm; 25 | pool->ptr = ptr; 26 | pool->array_size = array_size; 27 | pool->ob_size = ob_size; 28 | 29 | pool->constructor = constructor; 30 | pool->destructor = destructor; 31 | pool->check = check; 32 | pool->reset = reset; 33 | 34 | pthread_mutex_init(&(pool->mutex), NULL); 35 | 36 | return pool; 37 | } 38 | 39 | void mutex_pool_destroy(mutex_pool_t* pool) 40 | { 41 | pthread_mutex_destroy(&(pool->mutex)); 42 | 43 | while (pool->curr > 0){ 44 | void* ptr = pool->ptr[--pool->curr]; 45 | if (pool->destructor) 46 | pool->destructor(ptr); 47 | 48 | free(ptr); 49 | } 50 | 51 | free(pool->name); 52 | free(pool->ptr); 53 | free(pool); 54 | } 55 | 56 | void* mutex_pool_alloc(mutex_pool_t* pool) 57 | { 58 | void* ret; 59 | 60 | pthread_mutex_lock(&(pool->mutex)); 61 | 62 | if (pool->curr > 0){ 63 | ret = pool->ptr[--pool->curr]; 64 | pthread_mutex_unlock(&(pool->mutex)); 65 | } 66 | else{ 67 | pthread_mutex_unlock(&(pool->mutex)); 68 | 69 | ret = malloc(pool->ob_size); 70 | if (ret != NULL && pool->constructor(ret) != 0){ 71 | free(ret); 72 | ret = NULL; 73 | } 74 | } 75 | 76 | if (ret != NULL) 77 | pool->reset(ret, 1); 78 | 79 | return ret; 80 | } 81 | 82 | void mutex_pool_free(mutex_pool_t* pool, void* ob) 83 | { 84 | if (ob == NULL && pool->check(ob) != 0){ 85 | return; 86 | } 87 | 88 | pool->reset(ob, 0); 89 | 90 | pthread_mutex_lock(&(pool->mutex)); 91 | 92 | if (pool->curr < pool->array_size){ 93 | pool->ptr[pool->curr++] = ob; 94 | pthread_mutex_unlock(&(pool->mutex)); 95 | } 96 | else{ 97 | size_t new_size = 2 * pool->array_size; 98 | void** new_ptr = (void**)realloc(pool->ptr, sizeof(void *) * new_size); 99 | if (new_ptr != NULL){ 100 | pool->array_size = new_size; 101 | pool->ptr = new_ptr; 102 | pool->ptr[pool->curr++] = ob; 103 | 104 | pthread_mutex_unlock(&(pool->mutex)); 105 | } 106 | else{ 107 | pthread_mutex_unlock(&(pool->mutex)); 108 | 109 | pool->destructor(ob); 110 | free(ob); 111 | } 112 | } 113 | } 114 | 115 | void mutex_pool_print(mutex_pool_t* pool) 116 | { 117 | if (pool == NULL){ 118 | printf("%s pool's ptr = NULL!", pool->name); 119 | return; 120 | } 121 | printf("%s pool:\n", pool->name); 122 | printf("\t name = %s\n\tob size = %d\n\tarray size = %d\n\tcurr = %d\n", 123 | pool->name, (int)pool->ob_size, pool->array_size, pool->curr); 124 | } 125 | 126 | int32_t mutex_get_pool_info(mutex_pool_t* pool, char* buf) 127 | { 128 | int32_t pos = 0; 129 | assert(pool != NULL); 130 | 131 | pthread_mutex_lock(&(pool->mutex)); 132 | 133 | pos = sprintf(buf, "%s pool:\n", pool->name); 134 | pos += sprintf(buf + pos, "\tob size = %d\n\tarray size = %d\n\tcurr = %d\n", (int)pool->ob_size, pool->array_size, pool->curr); 135 | 136 | pthread_mutex_unlock(&(pool->mutex)); 137 | 138 | return pos; 139 | } 140 | 141 | 142 | 143 | 144 | 145 | -------------------------------------------------------------------------------- /wb_pthread_pool.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/yuanrongxi/lock-free-object-pool/1a9359b9f51a7b749a515480a99b2be31f8bf518/wb_pthread_pool.h -------------------------------------------------------------------------------- /wb_spin_lock.h: -------------------------------------------------------------------------------- 1 | #ifndef __SU_SPIN_LOCK_H_ 2 | #define __SU_SPIN_LOCK_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | 8 | #include "wb_gcc.h" 9 | 10 | typedef int spin_lock_t; 11 | 12 | static inline void lock_init(spin_lock_t* l); 13 | static inline void lock_lock(spin_lock_t* l); 14 | static inline void lock_clock(spin_lock_t* l, int count); 15 | static inline int lock_try_lock(spin_lock_t* l); 16 | static inline void lock_unlock(spin_lock_t* l); 17 | static inline void lock_destroy(spin_lock_t* l); 18 | 19 | typedef union 20 | { 21 | uint64_t u; 22 | uint32_t us; 23 | struct{ 24 | uint16_t writers; 25 | uint16_t readers; 26 | uint16_t users; 27 | uint16_t pad; 28 | } s; 29 | }rwlock_t; 30 | 31 | static inline int rwlock_init(rwlock_t* rwlock); 32 | static inline int rwlock_destroy(rwlock_t* rwlock); 33 | static inline int rwlock_try_rlock(rwlock_t* rwlock); 34 | static inline int rwlock_rlock(rwlock_t* rwlock); 35 | static inline int rwlock_runlock(rwlock_t* rwlock); 36 | static inline int rwlock_try_wlock(rwlock_t* rwlock); 37 | static inline int rwlock_wlock(rwlock_t* rwlock); 38 | static inline int rwlock_wunlock(rwlock_t* rwlock); 39 | 40 | #include "wb_spin_lock.inl" 41 | 42 | #endif 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /wb_spin_lock.inl: -------------------------------------------------------------------------------- 1 | static inline void lock_init(spin_lock_t* l) 2 | { 3 | *l = 0; 4 | } 5 | 6 | static inline void lock_lock(spin_lock_t* l) 7 | { 8 | int i; 9 | while (__sync_lock_test_and_set(l, 1)){ 10 | for (i = 0; i < 512; i++){ 11 | WT_PAUSE(); 12 | } 13 | 14 | if (*l == 1) sched_yield(); 15 | } 16 | }; 17 | 18 | static inline void lock_clock(spin_lock_t* l, int count) 19 | { 20 | int i; 21 | while (__sync_lock_test_and_set(l, 1)){ 22 | for (i = 0; i < count; i++) 23 | WT_PAUSE(); 24 | } 25 | } 26 | 27 | static inline int lock_try_lock(spin_lock_t* l) 28 | { 29 | if (__sync_lock_test_and_set(l, 1) != 0) 30 | return 1; 31 | 32 | return 0; 33 | } 34 | 35 | static inline void lock_unlock(spin_lock_t* l) 36 | { 37 | __sync_lock_release(l); 38 | } 39 | 40 | static inline void lock_destroy(spin_lock_t* l) 41 | { 42 | } 43 | 44 | int rwlock_init(rwlock_t* rwlock) 45 | { 46 | rwlock->u = 0; 47 | 48 | return 0; 49 | } 50 | 51 | int rwlock_destroy(rwlock_t* rwlock) 52 | { 53 | rwlock->u = 0; 54 | 55 | return 0; 56 | } 57 | 58 | int rwlock_try_rlock(rwlock_t* rwlock) 59 | { 60 | uint64_t old, ne, pad, users, writers; 61 | 62 | pad = rwlock->s.pad; 63 | users = rwlock->s.users; 64 | writers = rwlock->s.writers; 65 | 66 | old = (pad << 48) + (users << 32) + (users << 16) + writers; 67 | ne = (pad << 48) + ((users + 1) << 32) + ((users + 1) << 16) + writers; 68 | 69 | return (WT_ATOMIC_CAS_VAL8(rwlock->u, old, ne) == old ? 0 : -1); 70 | } 71 | 72 | int rwlock_rlock(rwlock_t* rwlock) 73 | { 74 | uint64_t me; 75 | uint16_t val; 76 | int pause_cnt; 77 | 78 | me = WT_ATOMIC_FETCH_ADD8(rwlock->u, (uint64_t)1 << 32); 79 | val = (uint16_t)(me >> 32); 80 | 81 | for (pause_cnt = 0; val != rwlock->s.readers;){ 82 | if (++pause_cnt < 1000) 83 | WT_PAUSE(); 84 | /*else 85 | su_sleep(0, 10);*/ 86 | } 87 | 88 | ++rwlock->s.readers; 89 | 90 | return 0; 91 | } 92 | 93 | int rwlock_runlock(rwlock_t* rwlock) 94 | { 95 | WT_ATOMIC_ADD2(rwlock->s.writers, 1); 96 | } 97 | 98 | int rwlock_try_wlock(rwlock_t* rwlock) 99 | { 100 | uint64_t old, ne, pad, readers, users; 101 | 102 | pad = rwlock->s.pad; 103 | readers = rwlock->s.readers; 104 | users = rwlock->s.users; 105 | 106 | old = (pad << 48) + (users << 32) + (readers << 16) + users; 107 | ne = (pad << 48) + ((users + 1) << 32) + (readers << 16) + users; 108 | 109 | return (WT_ATOMIC_CAS_VAL8(rwlock->u, old, ne) == old ? 0 : -1); 110 | } 111 | 112 | int rwlock_wlock(rwlock_t* rwlock) 113 | { 114 | uint64_t me; 115 | uint16_t val; 116 | 117 | me = WT_ATOMIC_FETCH_ADD8(rwlock->u, (uint64_t)1 << 32); 118 | val = (uint16_t)(me >> 32); 119 | while (val != rwlock->s.writers) 120 | WT_PAUSE(); 121 | 122 | return 0; 123 | } 124 | 125 | int rwlock_wunlock(rwlock_t* rwlock) 126 | { 127 | rwlock_t copy; 128 | 129 | copy = *rwlock; 130 | WT_BARRIER(); 131 | 132 | ++copy.s.writers; 133 | ++copy.s.readers; 134 | 135 | rwlock->us = copy.us; 136 | 137 | return 0; 138 | } 139 | --------------------------------------------------------------------------------