xref: /haiku/src/system/kernel/posix/realtime_sem.cpp (revision 820dca4df6c7bf955c46e8f6521b9408f50b2900)
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