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
27class SemInfo {
28public:
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
56private:
57	sem_id	fSemaphoreID;
58};
59
60
61class NamedSem : public SemInfo {
62public:
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
142private:
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
153class UnnamedSem : public SemInfo {
154public:
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
205private:
206	sem_id	fID;
207};
208
209
210class UnnamedSharedSem : public SemInfo {
211public:
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
246private:
247	UnnamedSharedSem*	fHashLink;
248};
249
250
251struct 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
277struct 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
303class GlobalSemTable {
304public:
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
444private:
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
455static GlobalSemTable sSemTable;
456
457
458class TeamSemInfo {
459public:
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
510private:
511	SemInfo*		fSemaphore;
512	sem_t*			fUserSemaphore;
513	int32			fOpenCount;
514
515	TeamSemInfo*	fHashLink;
516};
517
518
519struct 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
545struct 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
788private:
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
801private:
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
814static realtime_sem_context*
815get_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
844static status_t
845copy_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
871void
872realtime_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
880void
881delete_realtime_sem_context(realtime_sem_context* context)
882{
883	delete context;
884}
885
886
887realtime_sem_context*
888clone_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
900status_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
970status_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
997status_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
1011status_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
1037status_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
1048status_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