00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082
00083
00084
00085
00086
00087
00088 #include "gw-config.h"
00089
00090 #include <string.h>
00091 #include <unistd.h>
00092 #include <stdlib.h>
00093 #include <errno.h>
00094
00095 #include "gwassert.h"
00096 #include "list.h"
00097 #include "log.h"
00098 #include "thread.h"
00099 #include "gwmem.h"
00100
00101
00102 struct List
00103 {
00104 void **tab;
00105 long tab_size;
00106 long start;
00107 long len;
00108 Mutex *single_operation_lock;
00109 Mutex *permanent_lock;
00110 pthread_cond_t nonempty;
00111 long num_producers;
00112 };
00113
00114 #define INDEX(list, i) (((list)->start + i) % (list)->tab_size)
00115 #define GET(list, i) ((list)->tab[INDEX(list, i)])
00116
00117
00118 long gwthread_self(void);
00119
00120 static void lock(List *list);
00121 static void unlock(List *list);
00122 static void make_bigger(List *list, long items);
00123 static void delete_items_from_list(List *list, long pos, long count);
00124
00125
00126 List *gwlist_create_real(void)
00127 {
00128 List *list;
00129
00130 list = gw_malloc(sizeof(List));
00131 list->tab = NULL;
00132 list->tab_size = 0;
00133 list->start = 0;
00134 list->len = 0;
00135 list->single_operation_lock = mutex_create();
00136 list->permanent_lock = mutex_create();
00137 pthread_cond_init(&list->nonempty, NULL);
00138 list->num_producers = 0;
00139 return list;
00140 }
00141
00142
00143 void gwlist_destroy(List *list, gwlist_item_destructor_t *destructor)
00144 {
00145 void *item;
00146
00147 if (list == NULL)
00148 return;
00149
00150 if (destructor != NULL) {
00151 while ((item = gwlist_extract_first(list)) != NULL)
00152 destructor(item);
00153 }
00154
00155 mutex_destroy(list->permanent_lock);
00156 mutex_destroy(list->single_operation_lock);
00157 pthread_cond_destroy(&list->nonempty);
00158 gw_free(list->tab);
00159 gw_free(list);
00160 }
00161
00162
00163 long gwlist_len(List *list)
00164 {
00165 long len;
00166
00167 if (list == NULL)
00168 return 0;
00169 lock(list);
00170 len = list->len;
00171 unlock(list);
00172 return len;
00173 }
00174
00175
00176 void gwlist_append(List *list, void *item)
00177 {
00178 lock(list);
00179 make_bigger(list, 1);
00180 list->tab[INDEX(list, list->len)] = item;
00181 ++list->len;
00182 pthread_cond_signal(&list->nonempty);
00183 unlock(list);
00184 }
00185
00186
00187 void gwlist_append_unique(List *list, void *item, int (*cmp)(void *, void *))
00188 {
00189 void *it;
00190 long i;
00191
00192 lock(list);
00193 it = NULL;
00194 for (i = 0; i < list->len; ++i) {
00195 it = GET(list, i);
00196 if (cmp(it, item)) {
00197 break;
00198 }
00199 }
00200 if (i == list->len) {
00201
00202 make_bigger(list, 1);
00203 list->tab[INDEX(list, list->len)] = item;
00204 ++list->len;
00205 pthread_cond_signal(&list->nonempty);
00206 }
00207 unlock(list);
00208 }
00209
00210
00211 void gwlist_insert(List *list, long pos, void *item)
00212 {
00213 long i;
00214
00215 lock(list);
00216 gw_assert(pos >= 0);
00217 gw_assert(pos <= list->len);
00218
00219 make_bigger(list, 1);
00220 for (i = list->len; i > pos; --i)
00221 list->tab[INDEX(list, i)] = GET(list, i - 1);
00222 list->tab[INDEX(list, pos)] = item;
00223 ++list->len;
00224 pthread_cond_signal(&list->nonempty);
00225 unlock(list);
00226 }
00227
00228
00229 void gwlist_delete(List *list, long pos, long count)
00230 {
00231 lock(list);
00232 delete_items_from_list(list, pos, count);
00233 unlock(list);
00234 }
00235
00236
00237 long gwlist_delete_matching(List *list, void *pat, gwlist_item_matches_t *matches)
00238 {
00239 long i;
00240 long count;
00241
00242 lock(list);
00243
00244
00245
00246
00247 i = 0;
00248 count = 0;
00249 while (i < list->len) {
00250 if (matches(GET(list, i), pat)) {
00251 delete_items_from_list(list, i, 1);
00252 count++;
00253 } else {
00254 ++i;
00255 }
00256 }
00257 unlock(list);
00258
00259 return count;
00260 }
00261
00262
00263 long gwlist_delete_equal(List *list, void *item)
00264 {
00265 long i;
00266 long count;
00267
00268 lock(list);
00269
00270
00271
00272
00273 i = 0;
00274 count = 0;
00275 while (i < list->len) {
00276 if (GET(list, i) == item) {
00277 delete_items_from_list(list, i, 1);
00278 count++;
00279 } else {
00280 ++i;
00281 }
00282 }
00283 unlock(list);
00284
00285 return count;
00286 }
00287
00288
00289 void *gwlist_get(List *list, long pos)
00290 {
00291 void *item;
00292
00293 lock(list);
00294 gw_assert(pos >= 0);
00295 gw_assert(pos < list->len);
00296 item = GET(list, pos);
00297 unlock(list);
00298 return item;
00299 }
00300
00301
00302 void *gwlist_extract_first(List *list)
00303 {
00304 void *item;
00305
00306 gw_assert(list != NULL);
00307 lock(list);
00308 if (list->len == 0)
00309 item = NULL;
00310 else {
00311 item = GET(list, 0);
00312 delete_items_from_list(list, 0, 1);
00313 }
00314 unlock(list);
00315 return item;
00316 }
00317
00318
00319 List *gwlist_extract_matching(List *list, void *pat, gwlist_item_matches_t *cmp)
00320 {
00321 List *new_list;
00322 long i;
00323
00324 new_list = gwlist_create();
00325 lock(list);
00326 i = 0;
00327 while (i < list->len) {
00328 if (cmp(GET(list, i), pat)) {
00329 gwlist_append(new_list, GET(list, i));
00330 delete_items_from_list(list, i, 1);
00331 } else
00332 ++i;
00333 }
00334 unlock(list);
00335
00336 if (gwlist_len(new_list) == 0) {
00337 gwlist_destroy(new_list, NULL);
00338 return NULL;
00339 }
00340 return new_list;
00341 }
00342
00343
00344 void gwlist_lock(List *list)
00345 {
00346 gw_assert(list != NULL);
00347 mutex_lock(list->permanent_lock);
00348 }
00349
00350
00351 void gwlist_unlock(List *list)
00352 {
00353 gw_assert(list != NULL);
00354 mutex_unlock(list->permanent_lock);
00355 }
00356
00357
00358 int gwlist_wait_until_nonempty(List *list)
00359 {
00360 int ret;
00361
00362 lock(list);
00363 while (list->len == 0 && list->num_producers > 0) {
00364 list->single_operation_lock->owner = -1;
00365 pthread_cond_wait(&list->nonempty,
00366 &list->single_operation_lock->mutex);
00367 list->single_operation_lock->owner = gwthread_self();
00368 }
00369 if (list->len > 0)
00370 ret = 1;
00371 else
00372 ret = -1;
00373 unlock(list);
00374 return ret;
00375 }
00376
00377
00378 void gwlist_add_producer(List *list)
00379 {
00380 lock(list);
00381 ++list->num_producers;
00382 unlock(list);
00383 }
00384
00385
00386 int gwlist_producer_count(List *list)
00387 {
00388 int ret;
00389 lock(list);
00390 ret = list->num_producers;
00391 unlock(list);
00392 return ret;
00393 }
00394
00395
00396 void gwlist_remove_producer(List *list)
00397 {
00398 lock(list);
00399 gw_assert(list->num_producers > 0);
00400 --list->num_producers;
00401 pthread_cond_broadcast(&list->nonempty);
00402 unlock(list);
00403 }
00404
00405
00406 void gwlist_produce(List *list, void *item)
00407 {
00408 gwlist_append(list, item);
00409 }
00410
00411
00412 void *gwlist_consume(List *list)
00413 {
00414 void *item;
00415
00416 lock(list);
00417 while (list->len == 0 && list->num_producers > 0) {
00418 list->single_operation_lock->owner = -1;
00419 pthread_cond_wait(&list->nonempty,
00420 &list->single_operation_lock->mutex);
00421 list->single_operation_lock->owner = gwthread_self();
00422 }
00423 if (list->len > 0) {
00424 item = GET(list, 0);
00425 delete_items_from_list(list, 0, 1);
00426 } else {
00427 item = NULL;
00428 }
00429 unlock(list);
00430 return item;
00431 }
00432
00433
00434 void *gwlist_timed_consume(List *list, long sec)
00435 {
00436 void *item;
00437 struct timespec abstime;
00438 int rc;
00439
00440 abstime.tv_sec = time(NULL) + sec;
00441 abstime.tv_nsec = 0;
00442
00443 lock(list);
00444 while (list->len == 0 && list->num_producers > 0) {
00445 list->single_operation_lock->owner = -1;
00446 rc = pthread_cond_timedwait(&list->nonempty,
00447 &list->single_operation_lock->mutex, &abstime);
00448 list->single_operation_lock->owner = gwthread_self();
00449 if (rc == ETIMEDOUT)
00450 break;
00451 }
00452 if (list->len > 0) {
00453 item = GET(list, 0);
00454 delete_items_from_list(list, 0, 1);
00455 } else {
00456 item = NULL;
00457 }
00458 unlock(list);
00459 return item;
00460 }
00461
00462
00463 void *gwlist_search(List *list, void *pattern, int (*cmp)(void *, void *))
00464 {
00465 void *item;
00466 long i;
00467
00468 lock(list);
00469 item = NULL;
00470 for (i = 0; i < list->len; ++i) {
00471 item = GET(list, i);
00472 if (cmp(item, pattern)) {
00473 break;
00474 }
00475 }
00476 if (i == list->len) {
00477 item = NULL;
00478 }
00479 unlock(list);
00480
00481 return item;
00482 }
00483
00484
00485
00486 List *gwlist_search_all(List *list, void *pattern, int (*cmp)(void *, void *))
00487 {
00488 List *new_list;
00489 void *item;
00490 long i;
00491
00492 new_list = gwlist_create();
00493
00494 lock(list);
00495 item = NULL;
00496 for (i = 0; i < list->len; ++i) {
00497 item = GET(list, i);
00498 if (cmp(item, pattern))
00499 gwlist_append(new_list, item);
00500 }
00501 unlock(list);
00502
00503 if (gwlist_len(new_list) == 0) {
00504 gwlist_destroy(new_list, NULL);
00505 new_list = NULL;
00506 }
00507
00508 return new_list;
00509 }
00510
00511
00512 void gwlist_sort(List *list, int(*cmp)(const void *, const void *))
00513 {
00514 gw_assert(list != NULL && cmp != NULL);
00515
00516 lock(list);
00517 if (list->len == 0) {
00518
00519 unlock(list);
00520 return;
00521 }
00522 qsort(&GET(list, 0), list->len, sizeof(void*), cmp);
00523 unlock(list);
00524 }
00525
00526
00527
00528
00529 static void lock(List *list)
00530 {
00531 gw_assert(list != NULL);
00532 mutex_lock(list->single_operation_lock);
00533 }
00534
00535 static void unlock(List *list)
00536 {
00537 gw_assert(list != NULL);
00538 mutex_unlock(list->single_operation_lock);
00539 }
00540
00541
00542
00543
00544
00545
00546
00547
00548 static void make_bigger(List *list, long items)
00549 {
00550 long old_size, new_size;
00551 long len_at_beginning, len_at_end;
00552
00553 if (list->len + items <= list->tab_size)
00554 return;
00555
00556 old_size = list->tab_size;
00557 new_size = old_size + items;
00558 list->tab = gw_realloc(list->tab, new_size * sizeof(void *));
00559 list->tab_size = new_size;
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601 gw_assert(list->start < old_size ||
00602 (list->start == 0 && old_size == 0));
00603 if (list->start + list->len > old_size) {
00604 len_at_end = old_size - list->start;
00605 len_at_beginning = list->len - len_at_end;
00606 if (len_at_beginning <= new_size - old_size) {
00607
00608 memmove(list->tab + old_size,
00609 list->tab,
00610 len_at_beginning * sizeof(void *));
00611 } else {
00612
00613 memmove(list->tab + old_size,
00614 list->tab,
00615 (new_size - old_size) * sizeof(void *));
00616 memmove(list->tab,
00617 list->tab + (new_size - old_size),
00618 (len_at_beginning - (new_size - old_size))
00619 * sizeof(void *));
00620 }
00621 }
00622 }
00623
00624
00625
00626
00627
00628
00629 static void delete_items_from_list(List *list, long pos, long count)
00630 {
00631 long i, from, to;
00632
00633 gw_assert(pos >= 0);
00634 gw_assert(pos < list->len);
00635 gw_assert(count >= 0);
00636 gw_assert(pos + count <= list->len);
00637
00638
00639
00640
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650
00651
00652
00653
00654
00655
00656
00657 if (pos == 0) {
00658 list->start = (list->start + count) % list->tab_size;
00659 list->len -= count;
00660 } else if (pos + count == list->len) {
00661 list->len -= count;
00662 } else if (list->start + list->len < list->tab_size) {
00663 memmove(list->tab + list->start + pos,
00664 list->tab + list->start + pos + count,
00665 (list->len - pos - count) * sizeof(void *));
00666 list->len -= count;
00667 } else {
00668
00669
00670
00671
00672
00673 for (i = 0; i < list->len - count - pos; ++i) {
00674 from = INDEX(list, pos + i + count);
00675 to = INDEX(list, pos + i);
00676 list->tab[to] = list->tab[from];
00677 }
00678 list->len -= count;
00679 }
00680 }
See file LICENSE for details about the license agreement for using,
modifying, copying or deriving work from this software.