1 /* 2 * Copyright 2008-2011, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 #include <posix/realtime_sem.h> 7 8 #include <string.h> 9 10 #include <new> 11 12 #include <OS.h> 13 14 #include <AutoDeleter.h> 15 #include <fs/KPath.h> 16 #include <kernel.h> 17 #include <lock.h> 18 #include <syscall_restart.h> 19 #include <team.h> 20 #include <thread.h> 21 #include <util/atomic.h> 22 #include <util/AutoLock.h> 23 #include <util/khash.h> 24 #include <util/OpenHashTable.h> 25 26 27 class SemInfo { 28 public: 29 SemInfo() 30 : 31 fSemaphoreID(-1) 32 { 33 } 34 35 virtual ~SemInfo() 36 { 37 if (fSemaphoreID >= 0) 38 delete_sem(fSemaphoreID); 39 } 40 41 sem_id SemaphoreID() const { return fSemaphoreID; } 42 43 status_t Init(int32 semCount, const char* name) 44 { 45 fSemaphoreID = create_sem(semCount, name); 46 if (fSemaphoreID < 0) 47 return fSemaphoreID; 48 49 return B_OK; 50 } 51 52 virtual sem_id ID() const = 0; 53 virtual SemInfo* Clone() = 0; 54 virtual void Delete() = 0; 55 56 private: 57 sem_id fSemaphoreID; 58 }; 59 60 61 class NamedSem : public SemInfo { 62 public: 63 NamedSem() 64 : 65 fName(NULL), 66 fRefCount(1) 67 { 68 } 69 70 virtual ~NamedSem() 71 { 72 free(fName); 73 } 74 75 const char* Name() const { return fName; } 76 77 status_t Init(const char* name, mode_t mode, int32 semCount) 78 { 79 status_t error = SemInfo::Init(semCount, name); 80 if (error != B_OK) 81 return error; 82 83 fName = strdup(name); 84 if (fName == NULL) 85 return B_NO_MEMORY; 86 87 fUID = geteuid(); 88 fGID = getegid(); 89 fPermissions = mode; 90 91 return B_OK; 92 } 93 94 void AcquireReference() 95 { 96 atomic_add(&fRefCount, 1); 97 } 98 99 void ReleaseReference() 100 { 101 if (atomic_add(&fRefCount, -1) == 1) 102 delete this; 103 } 104 105 bool HasPermissions() const 106 { 107 if ((fPermissions & S_IWOTH) != 0) 108 return true; 109 110 uid_t uid = geteuid(); 111 if (uid == 0 || (uid == fUID && (fPermissions & S_IWUSR) != 0)) 112 return true; 113 114 gid_t gid = getegid(); 115 if (gid == fGID && (fPermissions & S_IWGRP) != 0) 116 return true; 117 118 return false; 119 } 120 121 virtual sem_id ID() const 122 { 123 return SemaphoreID(); 124 } 125 126 virtual SemInfo* Clone() 127 { 128 AcquireReference(); 129 return this; 130 } 131 132 virtual void Delete() 133 { 134 ReleaseReference(); 135 } 136 137 NamedSem*& HashLink() 138 { 139 return fHashLink; 140 } 141 142 private: 143 char* fName; 144 vint32 fRefCount; 145 uid_t fUID; 146 gid_t fGID; 147 mode_t fPermissions; 148 149 NamedSem* fHashLink; 150 }; 151 152 153 class UnnamedSem : public SemInfo { 154 public: 155 UnnamedSem() 156 : 157 fID(0) 158 { 159 } 160 161 virtual ~UnnamedSem() 162 { 163 } 164 165 status_t Init(int32 semCount, const char* name) 166 { 167 return SemInfo::Init(semCount, name); 168 } 169 170 void SetID(sem_id id) 171 { 172 fID = id; 173 } 174 175 virtual sem_id ID() const 176 { 177 return fID; 178 } 179 180 virtual SemInfo* Clone() 181 { 182 sem_info info; 183 if (get_sem_info(SemaphoreID(), &info) != B_OK) 184 return NULL; 185 186 UnnamedSem* clone = new(std::nothrow) UnnamedSem; 187 if (clone == NULL) 188 return NULL; 189 190 if (clone->Init(info.count, info.name) != B_OK) { 191 delete clone; 192 return NULL; 193 } 194 195 clone->SetID(fID); 196 197 return clone; 198 } 199 200 virtual void Delete() 201 { 202 delete this; 203 } 204 205 private: 206 sem_id fID; 207 }; 208 209 210 class UnnamedSharedSem : public SemInfo { 211 public: 212 UnnamedSharedSem() 213 { 214 } 215 216 virtual ~UnnamedSharedSem() 217 { 218 } 219 220 status_t Init(int32 semCount, const char* name) 221 { 222 return SemInfo::Init(semCount, name); 223 } 224 225 virtual sem_id ID() const 226 { 227 return SemaphoreID(); 228 } 229 230 virtual SemInfo* Clone() 231 { 232 // Can't be cloned. 233 return NULL; 234 } 235 236 virtual void Delete() 237 { 238 delete this; 239 } 240 241 UnnamedSharedSem*& HashLink() 242 { 243 return fHashLink; 244 } 245 246 private: 247 UnnamedSharedSem* fHashLink; 248 }; 249 250 251 struct NamedSemHashDefinition { 252 typedef const char* KeyType; 253 typedef NamedSem ValueType; 254 255 size_t HashKey(const KeyType& key) const 256 { 257 return hash_hash_string(key); 258 } 259 260 size_t Hash(NamedSem* semaphore) const 261 { 262 return HashKey(semaphore->Name()); 263 } 264 265 bool Compare(const KeyType& key, NamedSem* semaphore) const 266 { 267 return strcmp(key, semaphore->Name()) == 0; 268 } 269 270 NamedSem*& GetLink(NamedSem* semaphore) const 271 { 272 return semaphore->HashLink(); 273 } 274 }; 275 276 277 struct UnnamedSemHashDefinition { 278 typedef sem_id KeyType; 279 typedef UnnamedSharedSem ValueType; 280 281 size_t HashKey(const KeyType& key) const 282 { 283 return (size_t)key; 284 } 285 286 size_t Hash(UnnamedSharedSem* semaphore) const 287 { 288 return HashKey(semaphore->SemaphoreID()); 289 } 290 291 bool Compare(const KeyType& key, UnnamedSharedSem* semaphore) const 292 { 293 return key == semaphore->SemaphoreID(); 294 } 295 296 UnnamedSharedSem*& GetLink(UnnamedSharedSem* semaphore) const 297 { 298 return semaphore->HashLink(); 299 } 300 }; 301 302 303 class GlobalSemTable { 304 public: 305 GlobalSemTable() 306 : 307 fSemaphoreCount(0) 308 { 309 mutex_init(&fLock, "global named sem table"); 310 } 311 312 ~GlobalSemTable() 313 { 314 mutex_destroy(&fLock); 315 } 316 317 status_t Init() 318 { 319 status_t error = fNamedSemaphores.Init(); 320 if (error != B_OK) 321 return error; 322 return fUnnamedSemaphores.Init(); 323 } 324 325 status_t OpenNamedSem(const char* name, int openFlags, mode_t mode, 326 uint32 semCount, NamedSem*& _sem, bool& _created) 327 { 328 MutexLocker _(fLock); 329 330 NamedSem* sem = fNamedSemaphores.Lookup(name); 331 if (sem != NULL) { 332 if ((openFlags & O_EXCL) != 0) 333 return EEXIST; 334 335 if (!sem->HasPermissions()) 336 return EACCES; 337 338 sem->AcquireReference(); 339 _sem = sem; 340 _created = false; 341 return B_OK; 342 } 343 344 if ((openFlags & O_CREAT) == 0) 345 return ENOENT; 346 347 // does not exist yet -- create 348 if (fSemaphoreCount >= MAX_POSIX_SEMS) 349 return ENOSPC; 350 351 sem = new(std::nothrow) NamedSem; 352 if (sem == NULL) 353 return B_NO_MEMORY; 354 355 status_t error = sem->Init(name, mode, semCount); 356 if (error != B_OK) { 357 delete sem; 358 return error; 359 } 360 361 error = fNamedSemaphores.Insert(sem); 362 if (error != B_OK) { 363 delete sem; 364 return error; 365 } 366 367 // add one reference for the table 368 sem->AcquireReference(); 369 370 fSemaphoreCount++; 371 372 _sem = sem; 373 _created = true; 374 return B_OK; 375 } 376 377 status_t UnlinkNamedSem(const char* name) 378 { 379 MutexLocker _(fLock); 380 381 NamedSem* sem = fNamedSemaphores.Lookup(name); 382 if (sem == NULL) 383 return ENOENT; 384 385 if (!sem->HasPermissions()) 386 return EACCES; 387 388 fNamedSemaphores.Remove(sem); 389 sem->ReleaseReference(); 390 // release the table reference 391 fSemaphoreCount--; 392 393 return B_OK; 394 } 395 396 status_t CreateUnnamedSem(uint32 semCount, int32_t& _id) 397 { 398 MutexLocker _(fLock); 399 400 if (fSemaphoreCount >= MAX_POSIX_SEMS) 401 return ENOSPC; 402 403 UnnamedSharedSem* sem = new(std::nothrow) UnnamedSharedSem; 404 if (sem == NULL) 405 return B_NO_MEMORY; 406 407 status_t error = sem->Init(semCount, "unnamed shared sem"); 408 if (error == B_OK) 409 error = fUnnamedSemaphores.Insert(sem); 410 if (error != B_OK) { 411 delete sem; 412 return error; 413 } 414 415 fSemaphoreCount++; 416 417 _id = sem->SemaphoreID(); 418 return B_OK; 419 } 420 421 status_t DeleteUnnamedSem(sem_id id) 422 { 423 MutexLocker _(fLock); 424 425 UnnamedSharedSem* sem = fUnnamedSemaphores.Lookup(id); 426 if (sem == NULL) 427 return B_BAD_VALUE; 428 429 fUnnamedSemaphores.Remove(sem); 430 delete sem; 431 432 fSemaphoreCount--; 433 434 return B_OK; 435 } 436 437 bool IsUnnamedValidSem(sem_id id) 438 { 439 MutexLocker _(fLock); 440 441 return fUnnamedSemaphores.Lookup(id) != NULL; 442 } 443 444 private: 445 typedef BOpenHashTable<NamedSemHashDefinition, true> NamedSemTable; 446 typedef BOpenHashTable<UnnamedSemHashDefinition, true> UnnamedSemTable; 447 448 mutex fLock; 449 NamedSemTable fNamedSemaphores; 450 UnnamedSemTable fUnnamedSemaphores; 451 int32 fSemaphoreCount; 452 }; 453 454 455 static GlobalSemTable sSemTable; 456 457 458 class TeamSemInfo { 459 public: 460 TeamSemInfo(SemInfo* semaphore, sem_t* userSem) 461 : 462 fSemaphore(semaphore), 463 fUserSemaphore(userSem), 464 fOpenCount(1) 465 { 466 } 467 468 ~TeamSemInfo() 469 { 470 if (fSemaphore != NULL) 471 fSemaphore->Delete(); 472 } 473 474 sem_id ID() const { return fSemaphore->ID(); } 475 sem_id SemaphoreID() const { return fSemaphore->SemaphoreID(); } 476 sem_t* UserSemaphore() const { return fUserSemaphore; } 477 478 void Open() 479 { 480 fOpenCount++; 481 } 482 483 bool Close() 484 { 485 return --fOpenCount == 0; 486 } 487 488 TeamSemInfo* Clone() const 489 { 490 SemInfo* sem = fSemaphore->Clone(); 491 if (sem == NULL) 492 return NULL; 493 494 TeamSemInfo* clone = new(std::nothrow) TeamSemInfo(sem, fUserSemaphore); 495 if (clone == NULL) { 496 sem->Delete(); 497 return NULL; 498 } 499 500 clone->fOpenCount = fOpenCount; 501 502 return clone; 503 } 504 505 TeamSemInfo*& HashLink() 506 { 507 return fHashLink; 508 } 509 510 private: 511 SemInfo* fSemaphore; 512 sem_t* fUserSemaphore; 513 int32 fOpenCount; 514 515 TeamSemInfo* fHashLink; 516 }; 517 518 519 struct TeamSemHashDefinition { 520 typedef sem_id KeyType; 521 typedef TeamSemInfo ValueType; 522 523 size_t HashKey(const KeyType& key) const 524 { 525 return (size_t)key; 526 } 527 528 size_t Hash(TeamSemInfo* semaphore) const 529 { 530 return HashKey(semaphore->ID()); 531 } 532 533 bool Compare(const KeyType& key, TeamSemInfo* semaphore) const 534 { 535 return key == semaphore->ID(); 536 } 537 538 TeamSemInfo*& GetLink(TeamSemInfo* semaphore) const 539 { 540 return semaphore->HashLink(); 541 } 542 }; 543 544 545 struct realtime_sem_context { 546 realtime_sem_context() 547 : 548 fSemaphoreCount(0) 549 { 550 mutex_init(&fLock, "realtime sem context"); 551 } 552 553 ~realtime_sem_context() 554 { 555 mutex_lock(&fLock); 556 557 // delete all semaphores. 558 SemTable::Iterator it = fSemaphores.GetIterator(); 559 while (TeamSemInfo* sem = it.Next()) { 560 // Note, this uses internal knowledge about how the iterator works. 561 // Ugly, but there's no good alternative. 562 fSemaphores.RemoveUnchecked(sem); 563 delete sem; 564 } 565 566 mutex_destroy(&fLock); 567 } 568 569 status_t Init() 570 { 571 fNextPrivateSemID = -1; 572 return fSemaphores.Init(); 573 } 574 575 realtime_sem_context* Clone() 576 { 577 // create new context 578 realtime_sem_context* context = new(std::nothrow) realtime_sem_context; 579 if (context == NULL) 580 return NULL; 581 ObjectDeleter<realtime_sem_context> contextDeleter(context); 582 583 MutexLocker _(fLock); 584 585 context->fNextPrivateSemID = fNextPrivateSemID; 586 587 // clone all semaphores 588 SemTable::Iterator it = fSemaphores.GetIterator(); 589 while (TeamSemInfo* sem = it.Next()) { 590 TeamSemInfo* clonedSem = sem->Clone(); 591 if (clonedSem == NULL) 592 return NULL; 593 594 if (context->fSemaphores.Insert(clonedSem) != B_OK) { 595 delete clonedSem; 596 return NULL; 597 } 598 context->fSemaphoreCount++; 599 } 600 601 contextDeleter.Detach(); 602 return context; 603 } 604 605 status_t CreateUnnamedSem(uint32 semCount, bool shared, int32_t& _id) 606 { 607 if (shared) 608 return sSemTable.CreateUnnamedSem(semCount, _id); 609 610 UnnamedSem* sem = new(std::nothrow) UnnamedSem; 611 if (sem == NULL) 612 return B_NO_MEMORY; 613 ObjectDeleter<UnnamedSem> semDeleter(sem); 614 615 status_t error = sem->Init(semCount, "unnamed sem"); 616 if (error != B_OK) 617 return error; 618 619 TeamSemInfo* teamSem = new(std::nothrow) TeamSemInfo(sem, NULL); 620 if (teamSem == NULL) 621 return B_NO_MEMORY; 622 semDeleter.Detach(); 623 624 MutexLocker _(fLock); 625 626 if (fSemaphoreCount >= MAX_POSIX_SEMS_PER_TEAM) { 627 delete teamSem; 628 return ENOSPC; 629 } 630 631 sem->SetID(_NextPrivateSemID()); 632 633 error = fSemaphores.Insert(teamSem); 634 if (error != B_OK) { 635 delete teamSem; 636 return error; 637 } 638 639 fSemaphoreCount++; 640 641 _id = teamSem->ID(); 642 return B_OK; 643 } 644 645 status_t OpenSem(const char* name, int openFlags, mode_t mode, 646 uint32 semCount, sem_t* userSem, sem_t*& _usedUserSem, int32_t& _id, 647 bool& _created) 648 { 649 NamedSem* sem = NULL; 650 status_t error = sSemTable.OpenNamedSem(name, openFlags, mode, semCount, 651 sem, _created); 652 if (error != B_OK) 653 return error; 654 655 MutexLocker _(fLock); 656 657 TeamSemInfo* teamSem = fSemaphores.Lookup(sem->ID()); 658 if (teamSem != NULL) { 659 // already open -- just increment the open count 660 teamSem->Open(); 661 sem->ReleaseReference(); 662 _usedUserSem = teamSem->UserSemaphore(); 663 _id = teamSem->ID(); 664 return B_OK; 665 } 666 667 // not open yet -- create a new team sem 668 669 // first check the semaphore limit, though 670 if (fSemaphoreCount >= MAX_POSIX_SEMS_PER_TEAM) { 671 sem->ReleaseReference(); 672 if (_created) 673 sSemTable.UnlinkNamedSem(name); 674 return ENOSPC; 675 } 676 677 teamSem = new(std::nothrow) TeamSemInfo(sem, userSem); 678 if (teamSem == NULL) { 679 sem->ReleaseReference(); 680 if (_created) 681 sSemTable.UnlinkNamedSem(name); 682 return B_NO_MEMORY; 683 } 684 685 error = fSemaphores.Insert(teamSem); 686 if (error != B_OK) { 687 delete teamSem; 688 if (_created) 689 sSemTable.UnlinkNamedSem(name); 690 return error; 691 } 692 693 fSemaphoreCount++; 694 695 _usedUserSem = teamSem->UserSemaphore(); 696 _id = teamSem->ID(); 697 698 return B_OK; 699 } 700 701 status_t CloseSem(sem_id id, sem_t*& deleteUserSem) 702 { 703 deleteUserSem = NULL; 704 705 MutexLocker _(fLock); 706 707 TeamSemInfo* sem = fSemaphores.Lookup(id); 708 if (sem == NULL) 709 return sSemTable.DeleteUnnamedSem(id); 710 711 if (sem->Close()) { 712 // last reference closed 713 fSemaphores.Remove(sem); 714 fSemaphoreCount--; 715 deleteUserSem = sem->UserSemaphore(); 716 delete sem; 717 } 718 719 return B_OK; 720 } 721 722 status_t AcquireSem(sem_id id, bigtime_t timeout) 723 { 724 MutexLocker locker(fLock); 725 726 TeamSemInfo* sem = fSemaphores.Lookup(id); 727 if (sem == NULL) { 728 if (!sSemTable.IsUnnamedValidSem(id)) 729 return B_BAD_VALUE; 730 } else 731 id = sem->SemaphoreID(); 732 733 locker.Unlock(); 734 735 status_t error; 736 if (timeout == 0) { 737 error = acquire_sem_etc(id, 1, B_CAN_INTERRUPT | B_RELATIVE_TIMEOUT, 738 0); 739 } else if (timeout == B_INFINITE_TIMEOUT) { 740 error = acquire_sem_etc(id, 1, B_CAN_INTERRUPT, 0); 741 } else { 742 error = acquire_sem_etc(id, 1, 743 B_CAN_INTERRUPT | B_ABSOLUTE_REAL_TIME_TIMEOUT, timeout); 744 } 745 746 return error == B_BAD_SEM_ID ? B_BAD_VALUE : error; 747 } 748 749 status_t ReleaseSem(sem_id id) 750 { 751 MutexLocker locker(fLock); 752 753 TeamSemInfo* sem = fSemaphores.Lookup(id); 754 if (sem == NULL) { 755 if (!sSemTable.IsUnnamedValidSem(id)) 756 return B_BAD_VALUE; 757 } else 758 id = sem->SemaphoreID(); 759 760 locker.Unlock(); 761 762 status_t error = release_sem(id); 763 return error == B_BAD_SEM_ID ? B_BAD_VALUE : error; 764 } 765 766 status_t GetSemCount(sem_id id, int& _count) 767 { 768 MutexLocker locker(fLock); 769 770 TeamSemInfo* sem = fSemaphores.Lookup(id); 771 if (sem == NULL) { 772 if (!sSemTable.IsUnnamedValidSem(id)) 773 return B_BAD_VALUE; 774 } else 775 id = sem->SemaphoreID(); 776 777 locker.Unlock(); 778 779 int32 count; 780 status_t error = get_sem_count(id, &count); 781 if (error != B_OK) 782 return error; 783 784 _count = count; 785 return B_OK; 786 } 787 788 private: 789 sem_id _NextPrivateSemID() 790 { 791 while (true) { 792 if (fNextPrivateSemID >= 0) 793 fNextPrivateSemID = -1; 794 795 sem_id id = fNextPrivateSemID--; 796 if (fSemaphores.Lookup(id) == NULL) 797 return id; 798 } 799 } 800 801 private: 802 typedef BOpenHashTable<TeamSemHashDefinition, true> SemTable; 803 804 mutex fLock; 805 SemTable fSemaphores; 806 int32 fSemaphoreCount; 807 sem_id fNextPrivateSemID; 808 }; 809 810 811 // #pragma mark - implementation private 812 813 814 static realtime_sem_context* 815 get_current_team_context() 816 { 817 Team* team = thread_get_current_thread()->team; 818 819 // get context 820 realtime_sem_context* context = atomic_pointer_get( 821 &team->realtime_sem_context); 822 if (context != NULL) 823 return context; 824 825 // no context yet -- create a new one 826 context = new(std::nothrow) realtime_sem_context; 827 if (context == NULL || context->Init() != B_OK) { 828 delete context; 829 return NULL; 830 } 831 832 // set the allocated context 833 realtime_sem_context* oldContext = atomic_pointer_test_and_set( 834 &team->realtime_sem_context, context, (realtime_sem_context*)NULL); 835 if (oldContext == NULL) 836 return context; 837 838 // someone else was quicker 839 delete context; 840 return oldContext; 841 } 842 843 844 static status_t 845 copy_sem_name_to_kernel(const char* userName, KPath& buffer, char*& name) 846 { 847 if (userName == NULL) 848 return B_BAD_VALUE; 849 if (!IS_USER_ADDRESS(userName)) 850 return B_BAD_ADDRESS; 851 852 if (buffer.InitCheck() != B_OK) 853 return B_NO_MEMORY; 854 855 // copy userland path to kernel 856 name = buffer.LockBuffer(); 857 ssize_t actualLength = user_strlcpy(name, userName, buffer.BufferSize()); 858 859 if (actualLength < 0) 860 return B_BAD_ADDRESS; 861 if ((size_t)actualLength >= buffer.BufferSize()) 862 return ENAMETOOLONG; 863 864 return B_OK; 865 } 866 867 868 // #pragma mark - kernel internal 869 870 871 void 872 realtime_sem_init() 873 { 874 new(&sSemTable) GlobalSemTable; 875 if (sSemTable.Init() != B_OK) 876 panic("realtime_sem_init() failed to init global sem table"); 877 } 878 879 880 void 881 delete_realtime_sem_context(realtime_sem_context* context) 882 { 883 delete context; 884 } 885 886 887 realtime_sem_context* 888 clone_realtime_sem_context(realtime_sem_context* context) 889 { 890 if (context == NULL) 891 return NULL; 892 893 return context->Clone(); 894 } 895 896 897 // #pragma mark - syscalls 898 899 900 status_t 901 _user_realtime_sem_open(const char* userName, int openFlagsOrShared, 902 mode_t mode, uint32 semCount, sem_t* userSem, sem_t** _usedUserSem) 903 { 904 realtime_sem_context* context = get_current_team_context(); 905 if (context == NULL) 906 return B_NO_MEMORY; 907 908 if (semCount > MAX_POSIX_SEM_VALUE) 909 return B_BAD_VALUE; 910 911 // userSem must always be given 912 if (userSem == NULL) 913 return B_BAD_VALUE; 914 if (!IS_USER_ADDRESS(userSem)) 915 return B_BAD_ADDRESS; 916 917 // unnamed semaphores are less work -- deal with them first 918 if (userName == NULL) { 919 int32_t id; 920 status_t error = context->CreateUnnamedSem(semCount, openFlagsOrShared, 921 id); 922 if (error != B_OK) 923 return error; 924 925 if (user_memcpy(&userSem->id, &id, sizeof(int)) != B_OK) { 926 sem_t* dummy; 927 context->CloseSem(id, dummy); 928 return B_BAD_ADDRESS; 929 } 930 931 return B_OK; 932 } 933 934 // check user pointers 935 if (_usedUserSem == NULL) 936 return B_BAD_VALUE; 937 if (!IS_USER_ADDRESS(_usedUserSem) || !IS_USER_ADDRESS(userName)) 938 return B_BAD_ADDRESS; 939 940 // copy name to kernel 941 KPath nameBuffer(B_PATH_NAME_LENGTH); 942 char* name; 943 status_t error = copy_sem_name_to_kernel(userName, nameBuffer, name); 944 if (error != B_OK) 945 return error; 946 947 // open the semaphore 948 sem_t* usedUserSem; 949 bool created; 950 int32_t id; 951 error = context->OpenSem(name, openFlagsOrShared, mode, semCount, userSem, 952 usedUserSem, id, created); 953 if (error != B_OK) 954 return error; 955 956 // copy results back to userland 957 if (user_memcpy(&userSem->id, &id, sizeof(int)) != B_OK 958 || user_memcpy(_usedUserSem, &usedUserSem, sizeof(sem_t*)) != B_OK) { 959 if (created) 960 sSemTable.UnlinkNamedSem(name); 961 sem_t* dummy; 962 context->CloseSem(id, dummy); 963 return B_BAD_ADDRESS; 964 } 965 966 return B_OK; 967 } 968 969 970 status_t 971 _user_realtime_sem_close(sem_id semID, sem_t** _deleteUserSem) 972 { 973 if (_deleteUserSem != NULL && !IS_USER_ADDRESS(_deleteUserSem)) 974 return B_BAD_ADDRESS; 975 976 realtime_sem_context* context = get_current_team_context(); 977 if (context == NULL) 978 return B_BAD_VALUE; 979 980 // close sem 981 sem_t* deleteUserSem; 982 status_t error = context->CloseSem(semID, deleteUserSem); 983 if (error != B_OK) 984 return error; 985 986 // copy back result to userland 987 if (_deleteUserSem != NULL 988 && user_memcpy(_deleteUserSem, &deleteUserSem, sizeof(sem_t*)) 989 != B_OK) { 990 return B_BAD_ADDRESS; 991 } 992 993 return B_OK; 994 } 995 996 997 status_t 998 _user_realtime_sem_unlink(const char* userName) 999 { 1000 // copy name to kernel 1001 KPath nameBuffer(B_PATH_NAME_LENGTH); 1002 char* name; 1003 status_t error = copy_sem_name_to_kernel(userName, nameBuffer, name); 1004 if (error != B_OK) 1005 return error; 1006 1007 return sSemTable.UnlinkNamedSem(name); 1008 } 1009 1010 1011 status_t 1012 _user_realtime_sem_get_value(sem_id semID, int* _value) 1013 { 1014 if (_value == NULL) 1015 return B_BAD_VALUE; 1016 if (!IS_USER_ADDRESS(_value)) 1017 return B_BAD_ADDRESS; 1018 1019 realtime_sem_context* context = get_current_team_context(); 1020 if (context == NULL) 1021 return B_BAD_VALUE; 1022 1023 // get sem count 1024 int count; 1025 status_t error = context->GetSemCount(semID, count); 1026 if (error != B_OK) 1027 return error; 1028 1029 // copy back result to userland 1030 if (user_memcpy(_value, &count, sizeof(int)) != B_OK) 1031 return B_BAD_ADDRESS; 1032 1033 return B_OK; 1034 } 1035 1036 1037 status_t 1038 _user_realtime_sem_post(sem_id semID) 1039 { 1040 realtime_sem_context* context = get_current_team_context(); 1041 if (context == NULL) 1042 return B_BAD_VALUE; 1043 1044 return context->ReleaseSem(semID); 1045 } 1046 1047 1048 status_t 1049 _user_realtime_sem_wait(sem_id semID, bigtime_t timeout) 1050 { 1051 realtime_sem_context* context = get_current_team_context(); 1052 if (context == NULL) 1053 return B_BAD_VALUE; 1054 1055 return syscall_restart_handle_post(context->AcquireSem(semID, timeout)); 1056 } 1057