Changeset 367 for trunk/src/sh_inotify.c
- Timestamp:
- Oct 30, 2011, 9:18:31 AM (13 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/sh_inotify.c
r364 r367 51 51 52 52 #if defined(HAVE_PTHREAD) 53 54 SH_MUTEX_STATIC(mutex_list_dormant, PTHREAD_MUTEX_INITIALIZER); 55 SH_MUTEX_STATIC(mutex_watches, PTHREAD_MUTEX_INITIALIZER); 56 53 57 static pthread_key_t inotify_key; 54 58 static pthread_once_t inotify_key_once = PTHREAD_ONCE_INIT; … … 122 126 int watch; 123 127 int flag; 128 int class; 129 unsigned long check_mask; 124 130 char * file; 125 131 } sh_watch; … … 190 196 #define SH_INOTIFY_MODIFY 1 191 197 192 static void sh_inotify_init(sh_watches * watches) 193 { 198 void sh_inotify_init(sh_watches * watches) 199 { 200 SH_MUTEX_LOCK_UNSAFE(mutex_watches); 194 201 watches->list_of_watches = NULL; 195 202 watches->count = 0; 196 203 watches->max_count = 0; 204 SH_MUTEX_UNLOCK_UNSAFE(mutex_watches); 205 206 SH_MUTEX_LOCK_UNSAFE(mutex_list_dormant); 207 watches->dormant_watches = NULL; 208 SH_MUTEX_UNLOCK_UNSAFE(mutex_list_dormant); 209 197 210 return; 211 } 212 213 ssize_t sh_inotify_read(char * buffer, size_t count) 214 { 215 ssize_t len; 216 int ifd = sh_inotify_getfd(); 217 218 do { 219 len = read (ifd, &buffer, count); 220 } while (len < 0 || errno == EINTR); 221 222 return len; 198 223 } 199 224 … … 226 251 }; 227 252 253 static void sh_inotify_listitem_destroy(struct sh_inotify_litem * this) 254 { 255 if (this) 256 SH_FREE(this); 257 return; 258 } 259 260 /* No Mutex in the list cursor functions, must be in the caller 261 * function... 262 */ 228 263 typedef struct { 229 264 struct sh_inotify_litem *prenode; … … 231 266 } sh_inotify_listCursor; 232 267 233 static sh_watch * sh_inotify_list_first(sh_inotify_listCursor * listcursor, sh_watches * watches) 268 static sh_watch * sh_inotify_list_first(sh_inotify_listCursor * listcursor, 269 sh_watches * watches) 234 270 { 235 271 listcursor->prenode = watches->dormant_watches; 236 272 listcursor->curnode = watches->dormant_watches; 237 238 return listcursor->curnode->watch;239 }240 241 static sh_watch * sh_inotify_list_next(sh_inotify_listCursor * listcursor, sh_watches * watches)242 {243 (void) watches;244 245 listcursor->prenode = listcursor->curnode;246 listcursor->curnode = listcursor->curnode->next;247 273 248 274 if (listcursor->curnode) … … 251 277 } 252 278 253 static void sh_inotify_listitem_destroy(struct sh_inotify_litem * this) 254 { 255 SH_FREE(this); 256 return; 257 } 258 259 static sh_watch * sh_inotify_list_del_current(sh_inotify_listCursor * listcursor, sh_watches * watches) 279 static sh_watch * sh_inotify_list_next(sh_inotify_listCursor * listcursor, 280 sh_watches * watches) 281 { 282 (void) watches; 283 284 listcursor->prenode = listcursor->curnode; 285 286 if (listcursor->curnode) 287 { 288 listcursor->curnode = listcursor->curnode->next; 289 return listcursor->curnode->watch; 290 } 291 292 return NULL; 293 } 294 295 static sh_watch * sh_inotify_list_del_cur(sh_inotify_listCursor * listcursor, 296 sh_watches * watches) 260 297 { 261 298 sh_watch * ret = NULL; … … 277 314 listcursor->curnode = this->next; 278 315 } 279 ret = listcursor->curnode->watch; 316 if (listcursor->curnode) 317 ret = listcursor->curnode->watch; 318 else 319 ret = NULL; 280 320 sh_inotify_listitem_destroy(this); 281 321 } … … 285 325 static int sh_inotify_add_dormant(sh_watches * watches, sh_watch * item) 286 326 { 287 struct sh_inotify_litem * this = SH_ALLOC(sizeof(struct sh_inotify_litem)); 327 struct sh_inotify_litem * this; 328 329 SH_MUTEX_LOCK(mutex_list_dormant); 330 this = SH_ALLOC(sizeof(struct sh_inotify_litem)); 288 331 289 332 this->watch = item; … … 291 334 292 335 watches->dormant_watches = this; 336 SH_MUTEX_UNLOCK(mutex_list_dormant); 293 337 return 0; 338 } 339 340 static void * sh_dummy_popret = NULL; 341 342 char * sh_inotify_pop_dormant(sh_watches * watches, 343 int * class, unsigned long * check_mask) 344 { 345 char * popret = NULL; 346 struct sh_inotify_litem * this; 347 348 /* Take the address to keep gcc from putting it into a register. 349 * Avoids the 'clobbered by longjmp' warning. 350 */ 351 sh_dummy_popret = (void *) &popret; 352 353 SH_MUTEX_LOCK(mutex_list_dormant); 354 355 this = (struct sh_inotify_litem *) watches->dormant_watches; 356 357 if (this) 358 { 359 *class = this->watch->class; 360 *check_mask = this->watch->check_mask; 361 popret = sh_util_strdup(this->watch->file); 362 363 watches->dormant_watches = this->next; 364 365 sh_inotify_free_watch(this->watch); 366 SH_FREE(this); 367 } 368 SH_MUTEX_UNLOCK(mutex_list_dormant); 369 370 return popret; 371 } 372 373 void sh_inotify_purge_dormant(sh_watches * watches) 374 { 375 struct sh_inotify_litem * this; 376 377 SH_MUTEX_LOCK(mutex_list_dormant); 378 this = (struct sh_inotify_litem *) watches->dormant_watches; 379 380 watches->dormant_watches = NULL; 381 382 while (this) 383 { 384 struct sh_inotify_litem * cur = this; 385 386 this = this->next; 387 388 sh_inotify_free_watch(cur->watch); 389 SH_FREE(cur); 390 } 391 SH_MUTEX_UNLOCK(mutex_list_dormant); 392 return; 294 393 } 295 394 … … 308 407 { 309 408 int ifd = sh_inotify_getfd(); 310 zAVLTree * all_watches = (zAVLTree *)(watches->list_of_watches); 409 zAVLTree * all_watches; 410 411 SH_MUTEX_LOCK(mutex_watches); 412 all_watches = (zAVLTree *)(watches->list_of_watches); 311 413 312 414 if (all_watches) 313 415 zAVLFreeTree(all_watches, sh_inotify_free_watch); 314 416 315 sh_inotify_init(watches); 417 watches->list_of_watches = NULL; 418 watches->count = 0; 419 SH_MUTEX_UNLOCK(mutex_watches); 316 420 317 421 if (ifd >= 0) 318 422 close(ifd); 319 423 sh_set_inotify_fd(-1); 320 321 watches->count = 0;322 424 323 425 return; … … 345 447 } 346 448 449 #define SH_INOTIFY_FILEFLAGS \ 450 (IN_ATTRIB|IN_MODIFY|IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT) 451 #define SH_INOTIFY_DIRFLAGS \ 452 (SH_INOTIFY_FILEFLAGS|IN_DELETE|IN_CREATE|IN_MOVED_FROM|IN_MOVED_TO) 453 454 #define SH_INOTIFY_FLAGS (SH_INOTIFY_FILEFLAGS|SH_INOTIFY_DIRFLAGS) 455 456 /* Create an item and put it on the 'dormant' list for later watch creation 457 */ 458 int sh_inotify_add_watch_later(char * filename, sh_watches * watches, 459 int * errnum, 460 int class, unsigned long check_mask) 461 { 462 sh_watch * item; 463 464 item = sh_inotify_create_watch(filename, -1, /* flag */ 0); 465 466 item->class = class; 467 item->check_mask = check_mask; 468 469 sh_inotify_add_dormant(watches, item); 470 if (errnum) 471 *errnum = 0; 472 473 return 0; 474 } 475 476 int sh_inotify_rm_watch (sh_watches * watches, sh_watches * save, int wd) 477 { 478 int ifd = sh_get_inotify_fd(); 479 480 if (watches) 481 { 482 sh_watch * item; 483 484 SH_MUTEX_LOCK(mutex_watches); 485 item = zAVLSearch(watches->list_of_watches, &wd); 486 487 if (item) 488 { 489 zAVLDelete(watches->list_of_watches, &wd); 490 if (save) /* optionally save the item */ 491 { 492 item->watch = -1; 493 sh_inotify_add_dormant(save, item); 494 } 495 else 496 { 497 sh_inotify_free_watch(item); 498 } 499 } 500 SH_MUTEX_UNLOCK(mutex_watches); 501 } 502 return inotify_rm_watch(ifd, wd); 503 } 504 505 #if (defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)) 506 static void * sh_dummy_litem; 507 508 int sh_inotify_recheck_watches (sh_watches * watches, sh_watches * save) 509 { 510 sh_watch * litem; 511 sh_inotify_listCursor listcursor; 512 int ifd = sh_get_inotify_fd(); 513 514 extern void sh_fInotify_report_add(char * path, int class, unsigned long check_mask); 515 516 sh_dummy_litem = (void*) &litem; 517 518 /* -- Check dormant watches for reopening. 519 */ 520 SH_MUTEX_LOCK(mutex_list_dormant); 521 522 for (litem = sh_inotify_list_first(&listcursor, save); litem; 523 litem = sh_inotify_list_next(&listcursor, save)) 524 { 525 have_next: 526 527 /* sh_inotify_list_del_cur may return NULL */ 528 if (litem && litem->file && litem->watch == -1) 529 { 530 litem->watch = inotify_add_watch (ifd, litem->file, 531 SH_INOTIFY_FLAGS); 532 533 if (litem->watch >= 0) 534 { 535 SH_MUTEX_LOCK(mutex_watches); 536 if (watches->list_of_watches) 537 zAVLInsert(watches->list_of_watches, litem); 538 SH_MUTEX_UNLOCK(mutex_watches); 539 540 sh_fInotify_report_add(litem->file, litem->class, litem->check_mask); 541 542 litem = sh_inotify_list_del_cur(&listcursor, save); 543 544 goto have_next; 545 } 546 } 547 } 548 SH_MUTEX_UNLOCK(mutex_list_dormant); 549 return 0; 550 } 551 #endif 552 347 553 /* This function is idempotent; it will add the watch only once 348 554 */ 349 int sh_inotify_add_watch(char * filename, sh_watches * watches, int * errnum) 350 { 555 int sh_inotify_add_watch(char * filename, sh_watches * watches, int * errnum, 556 int class, unsigned long check_mask) 557 { 558 volatile int retval = 0; 559 560 SH_MUTEX_LOCK(mutex_watches); 561 351 562 *errnum = 0; 352 563 … … 375 586 376 587 nwatch = inotify_add_watch (ifd, filename, 377 IN_MODIFY|IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT);588 SH_INOTIFY_FLAGS); 378 589 if (nwatch < 0) 379 590 { 380 591 *errnum = errno; 381 return -1; 592 retval = -1; 593 goto retpoint; 382 594 } 383 595 384 596 item = sh_inotify_create_watch(filename, nwatch, /* flag */ 0); 597 598 item->class = class; 599 item->check_mask = check_mask; 385 600 386 601 if (NULL == watches->list_of_watches) 387 watches->list_of_watches = zAVLAllocTree (sh_inotify_getkey, zAVL_KEY_INT); 602 watches->list_of_watches = zAVLAllocTree (sh_inotify_getkey, 603 zAVL_KEY_INT); 388 604 389 605 if (watches->list_of_watches) 390 606 { 391 *errnum = zAVLInsert((zAVLTree *)(watches->list_of_watches), item); 607 *errnum = zAVLInsert((zAVLTree *)(watches->list_of_watches), 608 item); 609 392 610 if (*errnum != 0) 393 611 { 612 (*errnum == -1) ? *errnum = ENOMEM : EEXIST; 394 613 sh_inotify_free_watch(item); 395 return -1; 614 retval = -1; 615 goto retpoint; 396 616 } 397 617 } 398 618 else 399 619 { 400 *errnum = -1; 401 return -1; 620 *errnum = ENOMEM; 621 retval = -1; 622 goto retpoint; 402 623 } 403 624 … … 405 626 } 406 627 } 407 return 0; 408 } 628 retpoint: 629 SH_MUTEX_UNLOCK(mutex_watches); 630 return retval; 631 } 632 633 static void * sh_dummy_sret = NULL; 634 635 char * sh_inotify_search_item(sh_watches * watches, int watch, 636 int * class, unsigned long * check_mask) 637 { 638 sh_watch * item; 639 char * sret = NULL; 640 641 /* Take the address to keep gcc from putting it into a register. 642 * Avoids the 'clobbered by longjmp' warning. 643 */ 644 sh_dummy_sret = (void *) &sret; 645 646 SH_MUTEX_LOCK(mutex_watches); 647 item = zAVLSearch(watches->list_of_watches, &watch); 648 649 if (item) 650 { 651 *class = item->class; 652 *check_mask = item->check_mask; 653 sret = sh_util_strdup(item->file); 654 } 655 SH_MUTEX_UNLOCK(mutex_watches); 656 return sret; 657 } 658 659 static void * sh_dummy_litem = NULL; 409 660 410 661 int sh_inotify_wait_for_change(char * filename, sh_watches * watches, 411 662 int * errnum, int waitsec) 412 663 { 413 sh_watch * item;414 zAVLTree * all_watches = (zAVLTree *)(watches->list_of_watches);664 sh_watch * litem; 665 sh_watch * zitem; 415 666 int ifd = sh_inotify_getfd(); 416 667 668 /* Take the address to keep gcc from putting it into a register. 669 * Avoids the 'clobbered by longjmp' warning. 670 */ 671 sh_dummy_litem = (void*) &litem; 672 417 673 *errnum = 0; 418 674 … … 421 677 if (ifd >= 0) 422 678 { 679 volatile ssize_t i = 0; 423 680 ssize_t len = -1; 424 ssize_t i = 0;425 681 int flag = 0; 426 682 char buffer[1024]; … … 432 688 if (filename) 433 689 { 434 if (sh_inotify_add_watch(filename, watches, errnum ) < 0)690 if (sh_inotify_add_watch(filename, watches, errnum, 0, 0) < 0) 435 691 { 436 692 retry_msleep(waitsec, 0); … … 441 697 /* -- Check dormant watches for reopening. 442 698 */ 443 for (item = sh_inotify_list_first(&listcursor, watches); item; 444 item = sh_inotify_list_next(&listcursor, watches)) 699 SH_MUTEX_LOCK(mutex_list_dormant); 700 701 for (litem = sh_inotify_list_first(&listcursor, watches); litem; 702 litem = sh_inotify_list_next(&listcursor, watches)) 445 703 { 446 704 have_next: 447 if (item->file && item->watch == -1) 705 /* sh_inotify_list_del_cur may return NULL */ 706 if (litem && litem->file && litem->watch == -1) 448 707 { 449 item->watch = inotify_add_watch (ifd, item->file, 450 IN_MODIFY|IN_DELETE_SELF|IN_MOVE_SELF|IN_UNMOUNT); 451 if (item->watch >= 0) 708 litem->watch = inotify_add_watch (ifd, litem->file, 709 SH_INOTIFY_FLAGS); 710 711 if (litem->watch >= 0) 452 712 { 453 zAVLInsert(all_watches, item); 454 item = sh_inotify_list_del_current(&listcursor, watches); 713 SH_MUTEX_LOCK(mutex_watches); 714 if (watches->list_of_watches) 715 zAVLInsert(watches->list_of_watches, litem); 716 SH_MUTEX_UNLOCK(mutex_watches); 717 litem = sh_inotify_list_del_cur(&listcursor, watches); 455 718 goto have_next; 456 719 } 457 720 } 458 721 } 722 SH_MUTEX_UNLOCK(mutex_list_dormant); 459 723 460 724 461 725 /* -- Blocking read on inotify file descriptor 462 726 */ 463 do { 464 len = read (ifd, &buffer, sizeof(buffer)); 465 } while (len < 0 || errno == EINTR); 727 sh_inotify_read(buffer, sizeof(buffer)); 466 728 467 729 if (len > 0) … … 475 737 event = (struct inotify_event *) &buffer[i]; 476 738 477 item = zAVLSearch(all_watches, &(event->wd)); 478 479 if (item) 739 SH_MUTEX_LOCK(mutex_watches); 740 zitem = zAVLSearch(watches->list_of_watches, &(event->wd)); 741 742 if (zitem) 480 743 { 481 744 if (event->mask & IN_MODIFY) 482 745 { 483 item->flag |= SH_INOTIFY_MODIFY;746 zitem->flag |= SH_INOTIFY_MODIFY; 484 747 flag |= SH_INOTIFY_MODIFY; 485 748 } … … 488 751 event->mask & IN_MOVE_SELF ) 489 752 { 490 item->flag |= SH_INOTIFY_REOPEN;491 (void) inotify_rm_watch(ifd, item->watch);492 zAVLDelete( all_watches,item);493 sh_inotify_add_dormant(watches, item);494 item->watch = -1;753 zitem->flag |= SH_INOTIFY_REOPEN; 754 (void) inotify_rm_watch(ifd, zitem->watch); 755 zAVLDelete(watches->list_of_watches, zitem); 756 sh_inotify_add_dormant(watches, zitem); 757 zitem->watch = -1; 495 758 flag |= SH_INOTIFY_REOPEN; 496 759 } 497 760 } 761 SH_MUTEX_UNLOCK(mutex_watches); 498 762 499 763 i += sizeof (struct inotify_event) + event->len; … … 527 791 } 528 792 793 529 794 /* !defined(HAVE_SYS_INOTIFY_H) */ 530 795 #else … … 553 818 } 554 819 555 int sh_inotify_add_watch(char * filename, sh_watches * watches, int * errnum) 820 int sh_inotify_add_watch(char * filename, sh_watches * watches, int * errnum, 821 int class, unsigned long check_mask) 556 822 { 557 823 (void) filename; 558 824 (void) watches; 825 (void) class; 826 (void) check_mask; 559 827 *errnum = 0; 560 828 return 0; 561 829 } 562 830 831 int sh_inotify_add_watch_later(char * filename, sh_watches * watches, 832 int * errnum, 833 int class, unsigned long check_mask) 834 { 835 (void) filename; 836 (void) watches; 837 (void) class; 838 (void) check_mask; 839 *errnum = 0; 840 return 0; 841 } 842 563 843 #endif 844 845 #ifdef SH_CUTEST 846 #include "CuTest.h" 847 void Test_inotify(CuTest *tc) { 848 #if defined(HAVE_SYS_INOTIFY_H) && (defined(SH_WITH_CLIENT) || defined(SH_STANDALONE)) 849 850 int ret; 851 sh_watches twatch = SH_INOTIFY_INITIALIZER; 852 sh_watch * litem; 853 sh_inotify_listCursor listcursor; 854 char * p; 855 int class; 856 unsigned long check_mask; 857 int nrun = 0; 858 859 sh_watch aw1 = { -1, 0, 1, 1, "a1" }; 860 sh_watch aw2 = { -1, 0, 2, 1, "a2" }; 861 sh_watch aw3 = { 2, 0, 3, 1, "a3" }; 862 sh_watch aw4 = { -1, 0, 4, 1, "a4" }; 863 sh_watch aw5 = { 5, 0, 5, 1, "a5" }; 864 865 do { 866 867 int count = 0; 868 869 sh_watch * w1 = SH_ALLOC(sizeof(sh_watch)); 870 sh_watch * w2 = SH_ALLOC(sizeof(sh_watch)); 871 sh_watch * w3 = SH_ALLOC(sizeof(sh_watch)); 872 sh_watch * w4 = SH_ALLOC(sizeof(sh_watch)); 873 sh_watch * w5 = SH_ALLOC(sizeof(sh_watch)); 874 875 memcpy(w1, &aw1, sizeof(sh_watch)); 876 w1->file = sh_util_strdup(aw1.file); 877 memcpy(w2, &aw2, sizeof(sh_watch)); 878 w2->file = sh_util_strdup(aw2.file); 879 memcpy(w3, &aw3, sizeof(sh_watch)); 880 w3->file = sh_util_strdup(aw3.file); 881 memcpy(w4, &aw4, sizeof(sh_watch)); 882 w4->file = sh_util_strdup(aw4.file); 883 memcpy(w5, &aw5, sizeof(sh_watch)); 884 w5->file = sh_util_strdup(aw5.file); 885 886 ret = sh_inotify_add_dormant(&twatch, w1); 887 CuAssertIntEquals(tc, ret, 0); 888 ret = sh_inotify_add_dormant(&twatch, w2); 889 CuAssertIntEquals(tc, ret, 0); 890 ret = sh_inotify_add_dormant(&twatch, w3); 891 CuAssertIntEquals(tc, ret, 0); 892 ret = sh_inotify_add_dormant(&twatch, w4); 893 CuAssertIntEquals(tc, ret, 0); 894 ret = sh_inotify_add_dormant(&twatch, w5); 895 CuAssertIntEquals(tc, ret, 0); 896 897 /* -- Check dormant watches for reopening. 898 */ 899 for (litem = sh_inotify_list_first(&listcursor, &twatch); litem; 900 litem = sh_inotify_list_next(&listcursor, &twatch)) 901 { 902 have_next: 903 904 /* sh_inotify_list_del_cur may return NULL */ 905 if (litem) 906 { 907 ++count; 908 909 if (litem->file && litem->watch == -1) 910 { 911 912 switch (litem->class) 913 { 914 case 1: 915 CuAssertStrEquals(tc, litem->file, "a1"); 916 break; 917 case 2: 918 CuAssertStrEquals(tc, litem->file, "a2"); 919 break; 920 case 3: 921 CuAssertStrEquals(tc, litem->file, "deadbeef"); 922 break; 923 case 4: 924 CuAssertStrEquals(tc, litem->file, "a4"); 925 break; 926 case 5: 927 CuAssertStrEquals(tc, litem->file, "deadbeef"); 928 break; 929 default: 930 CuAssertStrEquals(tc, litem->file, "deadbeef"); 931 } 932 litem = sh_inotify_list_del_cur(&listcursor, &twatch); 933 goto have_next; 934 } 935 switch (litem->class) 936 { 937 case 3: 938 CuAssertStrEquals(tc, litem->file, "a3"); 939 break; 940 case 5: 941 CuAssertStrEquals(tc, litem->file, "a5"); 942 break; 943 default: 944 CuAssertStrEquals(tc, litem->file, "foobar"); 945 } 946 } 947 } 948 949 CuAssertIntEquals(tc, count, 5); 950 951 p = sh_inotify_pop_dormant(&twatch, &class, &check_mask); 952 CuAssertStrEquals(tc, p, "a5"); 953 954 p = sh_inotify_pop_dormant(&twatch, &class, &check_mask); 955 CuAssertStrEquals(tc, p, "a3"); 956 CuAssertIntEquals(tc, class, 3); 957 958 p = sh_inotify_pop_dormant(&twatch, &class, &check_mask); 959 CuAssertTrue(tc, NULL == p); 960 CuAssertTrue(tc, NULL == twatch.dormant_watches); 961 962 ++nrun; 963 964 } while (nrun < 100); 965 966 #else 967 (void) tc; 968 #endif 969 970 return; 971 } 972 #endif
Note:
See TracChangeset
for help on using the changeset viewer.