xref: /haiku/src/system/kernel/port.cpp (revision 7749d0bb0c358a3279b1b9cc76d8376e900130a5)
1 /*
2  * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
3  * Copyright 2002-2010, Axel Dörfler, axeld@pinc-software.de.
4  * Distributed under the terms of the MIT License.
5  *
6  * Copyright 2001, Mark-Jan Bastian. All rights reserved.
7  * Distributed under the terms of the NewOS License.
8  */
9 
10 
11 /*!	Ports for IPC */
12 
13 
14 #include <port.h>
15 
16 #include <ctype.h>
17 #include <iovec.h>
18 #include <stdlib.h>
19 #include <string.h>
20 
21 #include <OS.h>
22 
23 #include <AutoDeleter.h>
24 
25 #include <arch/int.h>
26 #include <heap.h>
27 #include <kernel.h>
28 #include <Notifications.h>
29 #include <sem.h>
30 #include <syscall_restart.h>
31 #include <team.h>
32 #include <tracing.h>
33 #include <util/AutoLock.h>
34 #include <util/list.h>
35 #include <vm/vm.h>
36 #include <wait_for_objects.h>
37 
38 
39 //#define TRACE_PORTS
40 #ifdef TRACE_PORTS
41 #	define TRACE(x) dprintf x
42 #else
43 #	define TRACE(x)
44 #endif
45 
46 
47 // Locking:
48 // * sPortsLock: Protects the sPorts hash table, Team::port_list, and
49 //   Port::owner.
50 // * Port::lock: Protects all Port members save team_link, hash_link, and lock.
51 //   id is immutable.
52 // * sPortQuotaLock: Protects sTotalSpaceInUse, sAreaChangeCounter,
53 //   sWaitingForSpace and the critical section of creating/adding areas for the
54 //   port heap in the grow case. It also has to be held when reading
55 //   sWaitingForSpace to determine whether or not to notify the
56 //   sNoSpaceCondition condition variable.
57 //
58 // The locking order is sPortsLock -> Port::lock. A port must be looked up
59 // in sPorts and locked with sPortsLock held. Afterwards sPortsLock can be
60 // dropped, unless any field guarded by sPortsLock is accessed.
61 
62 
63 struct port_message;
64 
65 
66 static void put_port_message(port_message* message);
67 
68 
69 struct port_message : DoublyLinkedListLinkImpl<port_message> {
70 	int32				code;
71 	size_t				size;
72 	uid_t				sender;
73 	gid_t				sender_group;
74 	team_id				sender_team;
75 	char				buffer[0];
76 };
77 
78 typedef DoublyLinkedList<port_message> MessageList;
79 
80 
81 struct Port {
82 	struct list_link	team_link;
83 	Port*				hash_link;
84 	port_id				id;
85 	team_id				owner;
86 	int32		 		capacity;
87 	mutex				lock;
88 	uint32				read_count;
89 	int32				write_count;
90 	ConditionVariable	read_condition;
91 	ConditionVariable	write_condition;
92 	int32				total_count;
93 		// messages read from port since creation
94 	select_info*		select_infos;
95 	MessageList			messages;
96 
97 	Port(team_id owner, int32 queueLength, char* name)
98 		:
99 		owner(owner),
100 		capacity(queueLength),
101 		read_count(0),
102 		write_count(queueLength),
103 		total_count(0),
104 		select_infos(NULL)
105 	{
106 		// id is initialized when the caller adds the port to the hash table
107 
108 		mutex_init(&lock, name);
109 		read_condition.Init(this, "port read");
110 		write_condition.Init(this, "port write");
111 	}
112 
113 	~Port()
114 	{
115 		while (port_message* message = messages.RemoveHead())
116 			put_port_message(message);
117 
118 		free((char*)lock.name);
119 		lock.name = NULL;
120 	}
121 };
122 
123 
124 struct PortHashDefinition {
125 	typedef port_id		KeyType;
126 	typedef	Port		ValueType;
127 
128 	size_t HashKey(port_id key) const
129 	{
130 		return key;
131 	}
132 
133 	size_t Hash(Port* value) const
134 	{
135 		return HashKey(value->id);
136 	}
137 
138 	bool Compare(port_id key, Port* value) const
139 	{
140 		return value->id == key;
141 	}
142 
143 	Port*& GetLink(Port* value) const
144 	{
145 		return value->hash_link;
146 	}
147 };
148 
149 typedef BOpenHashTable<PortHashDefinition> PortHashTable;
150 
151 
152 class PortNotificationService : public DefaultNotificationService {
153 public:
154 							PortNotificationService();
155 
156 			void			Notify(uint32 opcode, port_id team);
157 };
158 
159 
160 #if PORT_TRACING
161 namespace PortTracing {
162 
163 class Create : public AbstractTraceEntry {
164 public:
165 	Create(Port* port)
166 		:
167 		fID(port->id),
168 		fOwner(port->owner),
169 		fCapacity(port->capacity)
170 	{
171 		fName = alloc_tracing_buffer_strcpy(port->lock.name, B_OS_NAME_LENGTH,
172 			false);
173 
174 		Initialized();
175 	}
176 
177 	virtual void AddDump(TraceOutput& out)
178 	{
179 		out.Print("port %ld created, name \"%s\", owner %ld, capacity %ld",
180 			fID, fName, fOwner, fCapacity);
181 	}
182 
183 private:
184 	port_id				fID;
185 	char*				fName;
186 	team_id				fOwner;
187 	int32		 		fCapacity;
188 };
189 
190 
191 class Delete : public AbstractTraceEntry {
192 public:
193 	Delete(Port* port)
194 		:
195 		fID(port->id)
196 	{
197 		Initialized();
198 	}
199 
200 	virtual void AddDump(TraceOutput& out)
201 	{
202 		out.Print("port %ld deleted", fID);
203 	}
204 
205 private:
206 	port_id				fID;
207 };
208 
209 
210 class Read : public AbstractTraceEntry {
211 public:
212 	Read(port_id id, int32 readCount, int32 writeCount, int32 code,
213 		ssize_t result)
214 		:
215 		fID(id),
216 		fReadCount(readCount),
217 		fWriteCount(writeCount),
218 		fCode(code),
219 		fResult(result)
220 	{
221 		Initialized();
222 	}
223 
224 	virtual void AddDump(TraceOutput& out)
225 	{
226 		out.Print("port %ld read, read %ld, write %ld, code %lx: %ld",
227 			fID, fReadCount, fWriteCount, fCode, fResult);
228 	}
229 
230 private:
231 	port_id				fID;
232 	int32				fReadCount;
233 	int32				fWriteCount;
234 	int32				fCode;
235 	ssize_t				fResult;
236 };
237 
238 
239 class Write : public AbstractTraceEntry {
240 public:
241 	Write(port_id id, int32 readCount, int32 writeCount, int32 code,
242 		size_t bufferSize, ssize_t result)
243 		:
244 		fID(id),
245 		fReadCount(readCount),
246 		fWriteCount(writeCount),
247 		fCode(code),
248 		fBufferSize(bufferSize),
249 		fResult(result)
250 	{
251 		Initialized();
252 	}
253 
254 	virtual void AddDump(TraceOutput& out)
255 	{
256 		out.Print("port %ld write, read %ld, write %ld, code %lx, size %ld: %ld",
257 			fID, fReadCount, fWriteCount, fCode, fBufferSize, fResult);
258 	}
259 
260 private:
261 	port_id				fID;
262 	int32				fReadCount;
263 	int32				fWriteCount;
264 	int32				fCode;
265 	size_t				fBufferSize;
266 	ssize_t				fResult;
267 };
268 
269 
270 class Info : public AbstractTraceEntry {
271 public:
272 	Info(port_id id, int32 readCount, int32 writeCount, int32 code,
273 		ssize_t result)
274 		:
275 		fID(id),
276 		fReadCount(readCount),
277 		fWriteCount(writeCount),
278 		fCode(code),
279 		fResult(result)
280 	{
281 		Initialized();
282 	}
283 
284 	virtual void AddDump(TraceOutput& out)
285 	{
286 		out.Print("port %ld info, read %ld, write %ld, code %lx: %ld",
287 			fID, fReadCount, fWriteCount, fCode, fResult);
288 	}
289 
290 private:
291 	port_id				fID;
292 	int32				fReadCount;
293 	int32				fWriteCount;
294 	int32				fCode;
295 	ssize_t				fResult;
296 };
297 
298 
299 class OwnerChange : public AbstractTraceEntry {
300 public:
301 	OwnerChange(Port* port, team_id newOwner, status_t status)
302 		:
303 		fID(port->id),
304 		fOldOwner(port->owner),
305 		fNewOwner(newOwner),
306 		fStatus(status)
307 	{
308 		Initialized();
309 	}
310 
311 	virtual void AddDump(TraceOutput& out)
312 	{
313 		out.Print("port %ld owner change from %ld to %ld: %s", fID, fOldOwner,
314 			fNewOwner, strerror(fStatus));
315 	}
316 
317 private:
318 	port_id				fID;
319 	team_id				fOldOwner;
320 	team_id				fNewOwner;
321 	status_t	 		fStatus;
322 };
323 
324 }	// namespace PortTracing
325 
326 #	define T(x) new(std::nothrow) PortTracing::x;
327 #else
328 #	define T(x) ;
329 #endif
330 
331 
332 static const size_t kInitialPortBufferSize = 4 * 1024 * 1024;
333 static const size_t kTotalSpaceLimit = 64 * 1024 * 1024;
334 static const size_t kTeamSpaceLimit = 8 * 1024 * 1024;
335 static const size_t kBufferGrowRate = kInitialPortBufferSize;
336 
337 #define MAX_QUEUE_LENGTH 4096
338 #define PORT_MAX_MESSAGE_SIZE (256 * 1024)
339 
340 static int32 sMaxPorts = 4096;
341 static int32 sUsedPorts = 0;
342 
343 static PortHashTable sPorts;
344 static heap_allocator* sPortAllocator;
345 static ConditionVariable sNoSpaceCondition;
346 static int32 sTotalSpaceInUse;
347 static int32 sAreaChangeCounter;
348 static int32 sWaitingForSpace;
349 static port_id sNextPortID = 1;
350 static bool sPortsActive = false;
351 static mutex sPortsLock = MUTEX_INITIALIZER("ports list");
352 static mutex sPortQuotaLock = MUTEX_INITIALIZER("port quota");
353 
354 static PortNotificationService sNotificationService;
355 
356 
357 //	#pragma mark - TeamNotificationService
358 
359 
360 PortNotificationService::PortNotificationService()
361 	:
362 	DefaultNotificationService("ports")
363 {
364 }
365 
366 
367 void
368 PortNotificationService::Notify(uint32 opcode, port_id port)
369 {
370 	char eventBuffer[64];
371 	KMessage event;
372 	event.SetTo(eventBuffer, sizeof(eventBuffer), PORT_MONITOR);
373 	event.AddInt32("event", opcode);
374 	event.AddInt32("port", port);
375 
376 	DefaultNotificationService::Notify(event, opcode);
377 }
378 
379 
380 //	#pragma mark -
381 
382 
383 static int
384 dump_port_list(int argc, char** argv)
385 {
386 	const char* name = NULL;
387 	team_id owner = -1;
388 
389 	if (argc > 2) {
390 		if (!strcmp(argv[1], "team") || !strcmp(argv[1], "owner"))
391 			owner = strtoul(argv[2], NULL, 0);
392 		else if (!strcmp(argv[1], "name"))
393 			name = argv[2];
394 	} else if (argc > 1)
395 		owner = strtoul(argv[1], NULL, 0);
396 
397 	kprintf("port             id  cap  read-cnt  write-cnt   total   team  "
398 		"name\n");
399 
400 	for (PortHashTable::Iterator it = sPorts.GetIterator();
401 		Port* port = it.Next();) {
402 		if ((owner != -1 && port->owner != owner)
403 			|| (name != NULL && strstr(port->lock.name, name) == NULL))
404 			continue;
405 
406 		kprintf("%p %8ld %4ld %9ld %9ld %8ld %6ld  %s\n", port,
407 			port->id, port->capacity, port->read_count, port->write_count,
408 			port->total_count, port->owner, port->lock.name);
409 	}
410 
411 	return 0;
412 }
413 
414 
415 static void
416 _dump_port_info(Port* port)
417 {
418 	kprintf("PORT: %p\n", port);
419 	kprintf(" id:              %ld\n", port->id);
420 	kprintf(" name:            \"%s\"\n", port->lock.name);
421 	kprintf(" owner:           %ld\n", port->owner);
422 	kprintf(" capacity:        %ld\n", port->capacity);
423 	kprintf(" read_count:      %ld\n", port->read_count);
424 	kprintf(" write_count:     %ld\n", port->write_count);
425 	kprintf(" total count:     %ld\n", port->total_count);
426 
427 	if (!port->messages.IsEmpty()) {
428 		kprintf("messages:\n");
429 
430 		MessageList::Iterator iterator = port->messages.GetIterator();
431 		while (port_message* message = iterator.Next()) {
432 			kprintf(" %p  %08lx  %ld\n", message, message->code, message->size);
433 		}
434 	}
435 
436 	set_debug_variable("_port", (addr_t)port);
437 	set_debug_variable("_portID", port->id);
438 	set_debug_variable("_owner", port->owner);
439 }
440 
441 
442 static int
443 dump_port_info(int argc, char** argv)
444 {
445 	ConditionVariable* condition = NULL;
446 	const char* name = NULL;
447 
448 	if (argc < 2) {
449 		print_debugger_command_usage(argv[0]);
450 		return 0;
451 	}
452 
453 	if (argc > 2) {
454 		if (!strcmp(argv[1], "address")) {
455 			_dump_port_info((Port*)parse_expression(argv[2]));
456 			return 0;
457 		} else if (!strcmp(argv[1], "condition"))
458 			condition = (ConditionVariable*)parse_expression(argv[2]);
459 		else if (!strcmp(argv[1], "name"))
460 			name = argv[2];
461 	} else if (parse_expression(argv[1]) > 0) {
462 		// if the argument looks like a number, treat it as such
463 		int32 num = parse_expression(argv[1]);
464 		Port* port = sPorts.Lookup(num);
465 		if (port == NULL) {
466 			kprintf("port %ld (%#lx) doesn't exist!\n", num, num);
467 			return 0;
468 		}
469 		_dump_port_info(port);
470 		return 0;
471 	} else
472 		name = argv[1];
473 
474 	// walk through the ports list, trying to match name
475 	for (PortHashTable::Iterator it = sPorts.GetIterator();
476 		Port* port = it.Next();) {
477 		if ((name != NULL && port->lock.name != NULL
478 				&& !strcmp(name, port->lock.name))
479 			|| (condition != NULL && (&port->read_condition == condition
480 				|| &port->write_condition == condition))) {
481 			_dump_port_info(port);
482 			return 0;
483 		}
484 	}
485 
486 	return 0;
487 }
488 
489 
490 /*!	Notifies the port's select events.
491 	The port must be locked.
492 */
493 static void
494 notify_port_select_events(Port* port, uint16 events)
495 {
496 	if (port->select_infos)
497 		notify_select_events_list(port->select_infos, events);
498 }
499 
500 
501 static Port*
502 get_locked_port(port_id id)
503 {
504 	MutexLocker portsLocker(sPortsLock);
505 
506 	Port* port = sPorts.Lookup(id);
507 	if (port != NULL)
508 		mutex_lock(&port->lock);
509 	return port;
510 }
511 
512 
513 /*!	You need to own the port's lock when calling this function */
514 static inline bool
515 is_port_closed(Port* port)
516 {
517 	return port->capacity == 0;
518 }
519 
520 
521 static void
522 put_port_message(port_message* message)
523 {
524 	size_t size = sizeof(port_message) + message->size;
525 	heap_free(sPortAllocator, message);
526 
527 	MutexLocker quotaLocker(sPortQuotaLock);
528 	sTotalSpaceInUse -= size;
529 	if (sWaitingForSpace > 0)
530 		sNoSpaceCondition.NotifyAll();
531 }
532 
533 
534 static status_t
535 get_port_message(int32 code, size_t bufferSize, uint32 flags, bigtime_t timeout,
536 	port_message** _message, Port& port)
537 {
538 	size_t size = sizeof(port_message) + bufferSize;
539 	bool needToWait = false;
540 
541 	MutexLocker quotaLocker(sPortQuotaLock);
542 
543 	while (true) {
544 		while (sTotalSpaceInUse + size > kTotalSpaceLimit || needToWait) {
545 			// TODO: add per team limit
546 			// We are not allowed to create another heap area, as our
547 			// space limit has been reached - just wait until we get
548 			// some free space again.
549 
550 			// TODO: we don't want to wait - but does that also mean we
551 			// shouldn't wait for the area creation?
552 			if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0)
553 				return B_WOULD_BLOCK;
554 
555 			ConditionVariableEntry entry;
556 			sNoSpaceCondition.Add(&entry);
557 
558 			sWaitingForSpace++;
559 			quotaLocker.Unlock();
560 
561 			port_id portID = port.id;
562 			mutex_unlock(&port.lock);
563 
564 			status_t status = entry.Wait(flags, timeout);
565 
566 			// re-lock the port and the quota
567 			Port* newPort = get_locked_port(portID);
568 			quotaLocker.Lock();
569 			sWaitingForSpace--;
570 
571 			if (newPort != &port || is_port_closed(&port)) {
572 				// the port is no longer usable
573 				return B_BAD_PORT_ID;
574 			}
575 
576 			if (status == B_TIMED_OUT)
577 				return B_TIMED_OUT;
578 
579 			needToWait = false;
580 			continue;
581 		}
582 
583 		int32 areaChangeCounter = sAreaChangeCounter;
584 		sTotalSpaceInUse += size;
585 		quotaLocker.Unlock();
586 
587 		// Quota is fulfilled, try to allocate the buffer
588 
589 		port_message* message
590 			= (port_message*)heap_memalign(sPortAllocator, 0, size);
591 		if (message != NULL) {
592 			message->code = code;
593 			message->size = bufferSize;
594 
595 			*_message = message;
596 			return B_OK;
597 		}
598 
599 		quotaLocker.Lock();
600 
601 		// We weren't able to allocate and we'll start over, including
602 		// re-acquireing the quota, so we remove our size from the in-use
603 		// counter again.
604 		sTotalSpaceInUse -= size;
605 
606 		if (areaChangeCounter != sAreaChangeCounter) {
607 			// There was already an area added since we tried allocating,
608 			// start over.
609 			continue;
610 		}
611 
612 		// Create a new area for the heap to use
613 
614 		addr_t base;
615 		area_id area = create_area("port grown buffer", (void**)&base,
616 			B_ANY_KERNEL_ADDRESS, kBufferGrowRate, B_NO_LOCK,
617 			B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
618 		if (area < 0) {
619 			// We'll have to get by with what we have, so wait for someone
620 			// to free a message instead. We enforce waiting so that we don't
621 			// try to create a new area over and over.
622 			needToWait = true;
623 			continue;
624 		}
625 
626 		heap_add_area(sPortAllocator, area, base, kBufferGrowRate);
627 
628 		sAreaChangeCounter++;
629 		if (sWaitingForSpace > 0)
630 			sNoSpaceCondition.NotifyAll();
631 	}
632 }
633 
634 
635 /*!	Fills the port_info structure with information from the specified
636 	port.
637 	The port's lock must be held when called.
638 */
639 static void
640 fill_port_info(Port* port, port_info* info, size_t size)
641 {
642 	info->port = port->id;
643 	info->team = port->owner;
644 	info->capacity = port->capacity;
645 
646 	info->queue_count = port->read_count;
647 	info->total_count = port->total_count;
648 
649 	strlcpy(info->name, port->lock.name, B_OS_NAME_LENGTH);
650 }
651 
652 
653 static ssize_t
654 copy_port_message(port_message* message, int32* _code, void* buffer,
655 	size_t bufferSize, bool userCopy)
656 {
657 	// check output buffer size
658 	size_t size = min_c(bufferSize, message->size);
659 
660 	// copy message
661 	if (_code != NULL)
662 		*_code = message->code;
663 
664 	if (size > 0) {
665 		if (userCopy) {
666 			status_t status = user_memcpy(buffer, message->buffer, size);
667 			if (status != B_OK)
668 				return status;
669 		} else
670 			memcpy(buffer, message->buffer, size);
671 	}
672 
673 	return size;
674 }
675 
676 
677 static void
678 uninit_port_locked(Port* port)
679 {
680 	notify_port_select_events(port, B_EVENT_INVALID);
681 	port->select_infos = NULL;
682 
683 	// Release the threads that were blocking on this port.
684 	// read_port() will see the B_BAD_PORT_ID return value, and act accordingly
685 	port->read_condition.NotifyAll(false, B_BAD_PORT_ID);
686 	port->write_condition.NotifyAll(false, B_BAD_PORT_ID);
687 	sNotificationService.Notify(PORT_REMOVED, port->id);
688 }
689 
690 
691 //	#pragma mark - private kernel API
692 
693 
694 /*! This function deletes all the ports that are owned by the passed team.
695 */
696 void
697 delete_owned_ports(Team* team)
698 {
699 	TRACE(("delete_owned_ports(owner = %ld)\n", team->id));
700 
701 	MutexLocker portsLocker(sPortsLock);
702 
703 	// move the ports from the team's port list to a local list
704 	struct list queue;
705 	list_move_to_list(&team->port_list, &queue);
706 
707 	// iterate through the list or ports, remove them from the hash table and
708 	// uninitialize them
709 	Port* port = (Port*)list_get_first_item(&queue);
710 	while (port != NULL) {
711 		MutexLocker locker(port->lock);
712 		sPorts.Remove(port);
713 		uninit_port_locked(port);
714 		sUsedPorts--;
715 
716 		port = (Port*)list_get_next_item(&queue, port);
717 	}
718 
719 	portsLocker.Unlock();
720 
721 	// delete the ports
722 	while (Port* port = (Port*)list_remove_head_item(&queue))
723 		delete port;
724 }
725 
726 
727 int32
728 port_max_ports(void)
729 {
730 	return sMaxPorts;
731 }
732 
733 
734 int32
735 port_used_ports(void)
736 {
737 	return sUsedPorts;
738 }
739 
740 
741 status_t
742 port_init(kernel_args *args)
743 {
744 	// initialize ports table
745 	new(&sPorts) PortHashTable;
746 	if (sPorts.Init() != B_OK) {
747 		panic("Failed to init port hash table!");
748 		return B_NO_MEMORY;
749 	}
750 
751 	addr_t base;
752 	if (create_area("port heap", (void**)&base, B_ANY_KERNEL_ADDRESS,
753 			kInitialPortBufferSize, B_NO_LOCK,
754 			B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA) < 0) {
755 			// TODO: Since port_init() is invoked before the boot partition is
756 			// mounted, the underlying VMAnonymousCache cannot commit swap space
757 			// upon creation and thus the pages aren't swappable after all. This
758 			// makes the area essentially B_LAZY_LOCK with additional overhead.
759 		panic("unable to allocate port area!\n");
760 		return B_ERROR;
761 	}
762 
763 	static const heap_class kBufferHeapClass = { "port heap", 100,
764 		PORT_MAX_MESSAGE_SIZE + sizeof(port_message), 2 * 1024,
765 		sizeof(port_message), 4, 2, 24 };
766 	sPortAllocator = heap_create_allocator("port buffer", base,
767 		kInitialPortBufferSize, &kBufferHeapClass, true);
768 	if (sPortAllocator == NULL) {
769 		panic("unable to create port heap");
770 		return B_NO_MEMORY;
771 	}
772 
773 	sNoSpaceCondition.Init(&sPorts, "port space");
774 
775 	// add debugger commands
776 	add_debugger_command_etc("ports", &dump_port_list,
777 		"Dump a list of all active ports (for team, with name, etc.)",
778 		"[ ([ \"team\" | \"owner\" ] <team>) | (\"name\" <name>) ]\n"
779 		"Prints a list of all active ports meeting the given\n"
780 		"requirement. If no argument is given, all ports are listed.\n"
781 		"  <team>             - The team owning the ports.\n"
782 		"  <name>             - Part of the name of the ports.\n", 0);
783 	add_debugger_command_etc("port", &dump_port_info,
784 		"Dump info about a particular port",
785 		"(<id> | [ \"address\" ] <address>) | ([ \"name\" ] <name>) "
786 			"| (\"condition\" <address>)\n"
787 		"Prints info about the specified port.\n"
788 		"  <address>   - Pointer to the port structure.\n"
789 		"  <name>      - Name of the port.\n"
790 		"  <condition> - address of the port's read or write condition.\n", 0);
791 
792 	new(&sNotificationService) PortNotificationService();
793 	sPortsActive = true;
794 	return B_OK;
795 }
796 
797 
798 //	#pragma mark - public kernel API
799 
800 
801 port_id
802 create_port(int32 queueLength, const char* name)
803 {
804 	TRACE(("create_port(queueLength = %ld, name = \"%s\")\n", queueLength,
805 		name));
806 
807 	if (!sPortsActive) {
808 		panic("ports used too early!\n");
809 		return B_BAD_PORT_ID;
810 	}
811 	if (queueLength < 1 || queueLength > MAX_QUEUE_LENGTH)
812 		return B_BAD_VALUE;
813 
814 	Team* team = thread_get_current_thread()->team;
815 	if (team == NULL)
816 		return B_BAD_TEAM_ID;
817 
818 	// check & dup name
819 	char* nameBuffer = strdup(name != NULL ? name : "unnamed port");
820 	if (nameBuffer == NULL)
821 		return B_NO_MEMORY;
822 
823 	// create a port
824 	Port* port = new(std::nothrow) Port(team_get_current_team_id(), queueLength,
825 		nameBuffer);
826 	if (port == NULL) {
827 		free(nameBuffer);
828 		return B_NO_MEMORY;
829 	}
830 	ObjectDeleter<Port> portDeleter(port);
831 
832 	MutexLocker locker(sPortsLock);
833 
834 	// check the ports limit
835 	if (sUsedPorts >= sMaxPorts)
836 		return B_NO_MORE_PORTS;
837 
838 	sUsedPorts++;
839 
840 	// allocate a port ID
841 	do {
842 		port->id = sNextPortID++;
843 
844 		// handle integer overflow
845 		if (sNextPortID < 0)
846 			sNextPortID = 1;
847 	} while (sPorts.Lookup(port->id) != NULL);
848 
849 	// insert port in table and team list
850 	sPorts.Insert(port);
851 	list_add_item(&team->port_list, &port->team_link);
852 	portDeleter.Detach();
853 
854 	// tracing, notifications, etc.
855 	T(Create(port));
856 
857 	port_id id = port->id;
858 
859 	locker.Unlock();
860 
861 	TRACE(("create_port() done: port created %ld\n", id));
862 
863 	sNotificationService.Notify(PORT_ADDED, id);
864 	return id;
865 }
866 
867 
868 status_t
869 close_port(port_id id)
870 {
871 	TRACE(("close_port(id = %ld)\n", id));
872 
873 	if (!sPortsActive || id < 0)
874 		return B_BAD_PORT_ID;
875 
876 	// get the port
877 	Port* port = get_locked_port(id);
878 	if (port == NULL) {
879 		TRACE(("close_port: invalid port_id %ld\n", id));
880 		return B_BAD_PORT_ID;
881 	}
882 	MutexLocker lock(&port->lock, true);
883 
884 	// mark port to disable writing - deleting the semaphores will
885 	// wake up waiting read/writes
886 	port->capacity = 0;
887 
888 	notify_port_select_events(port, B_EVENT_INVALID);
889 	port->select_infos = NULL;
890 
891 	port->read_condition.NotifyAll(false, B_BAD_PORT_ID);
892 	port->write_condition.NotifyAll(false, B_BAD_PORT_ID);
893 
894 	return B_OK;
895 }
896 
897 
898 status_t
899 delete_port(port_id id)
900 {
901 	TRACE(("delete_port(id = %ld)\n", id));
902 
903 	if (!sPortsActive || id < 0)
904 		return B_BAD_PORT_ID;
905 
906 	// get the port and remove it from the hash table and the team
907 	Port* port;
908 	MutexLocker locker;
909 	{
910 		MutexLocker portsLocker(sPortsLock);
911 
912 		port = sPorts.Lookup(id);
913 		if (port == NULL) {
914 			TRACE(("delete_port: invalid port_id %ld\n", id));
915 			return B_BAD_PORT_ID;
916 		}
917 
918 		sPorts.Remove(port);
919 		list_remove_link(&port->team_link);
920 
921 		sUsedPorts--;
922 
923 		locker.SetTo(port->lock, false);
924 
925 		uninit_port_locked(port);
926 	}
927 
928 	T(Delete(port));
929 
930 	locker.Unlock();
931 
932 	delete port;
933 
934 	return B_OK;
935 }
936 
937 
938 status_t
939 select_port(int32 id, struct select_info* info, bool kernel)
940 {
941 	if (id < 0)
942 		return B_BAD_PORT_ID;
943 
944 	// get the port
945 	Port* port = get_locked_port(id);
946 	if (port == NULL)
947 		return B_BAD_PORT_ID;
948 	MutexLocker locker(port->lock, true);
949 
950 	// port must not yet be closed
951 	if (is_port_closed(port))
952 		return B_BAD_PORT_ID;
953 
954 	if (!kernel && port->owner == team_get_kernel_team_id()) {
955 		// kernel port, but call from userland
956 		return B_NOT_ALLOWED;
957 	}
958 
959 	info->selected_events &= B_EVENT_READ | B_EVENT_WRITE | B_EVENT_INVALID;
960 
961 	if (info->selected_events != 0) {
962 		uint16 events = 0;
963 
964 		info->next = port->select_infos;
965 		port->select_infos = info;
966 
967 		// check for events
968 		if ((info->selected_events & B_EVENT_READ) != 0
969 			&& !port->messages.IsEmpty()) {
970 			events |= B_EVENT_READ;
971 		}
972 
973 		if (port->write_count > 0)
974 			events |= B_EVENT_WRITE;
975 
976 		if (events != 0)
977 			notify_select_events(info, events);
978 	}
979 
980 	return B_OK;
981 }
982 
983 
984 status_t
985 deselect_port(int32 id, struct select_info* info, bool kernel)
986 {
987 	if (id < 0)
988 		return B_BAD_PORT_ID;
989 	if (info->selected_events == 0)
990 		return B_OK;
991 
992 	// get the port
993 	Port* port = get_locked_port(id);
994 	if (port == NULL)
995 		return B_BAD_PORT_ID;
996 	MutexLocker locker(port->lock, true);
997 
998 	// find and remove the infos
999 	select_info** infoLocation = &port->select_infos;
1000 	while (*infoLocation != NULL && *infoLocation != info)
1001 		infoLocation = &(*infoLocation)->next;
1002 
1003 	if (*infoLocation == info)
1004 		*infoLocation = info->next;
1005 
1006 	return B_OK;
1007 }
1008 
1009 
1010 port_id
1011 find_port(const char* name)
1012 {
1013 	TRACE(("find_port(name = \"%s\")\n", name));
1014 
1015 	if (!sPortsActive) {
1016 		panic("ports used too early!\n");
1017 		return B_NAME_NOT_FOUND;
1018 	}
1019 	if (name == NULL)
1020 		return B_BAD_VALUE;
1021 
1022 	MutexLocker portsLocker(sPortsLock);
1023 
1024 	for (PortHashTable::Iterator it = sPorts.GetIterator();
1025 		Port* port = it.Next();) {
1026 		if (!strcmp(name, port->lock.name))
1027 			return port->id;
1028 	}
1029 
1030 	return B_NAME_NOT_FOUND;
1031 }
1032 
1033 
1034 status_t
1035 _get_port_info(port_id id, port_info* info, size_t size)
1036 {
1037 	TRACE(("get_port_info(id = %ld)\n", id));
1038 
1039 	if (info == NULL || size != sizeof(port_info))
1040 		return B_BAD_VALUE;
1041 	if (!sPortsActive || id < 0)
1042 		return B_BAD_PORT_ID;
1043 
1044 	// get the port
1045 	Port* port = get_locked_port(id);
1046 	if (port == NULL) {
1047 		TRACE(("get_port_info: invalid port_id %ld\n", id));
1048 		return B_BAD_PORT_ID;
1049 	}
1050 	MutexLocker locker(port->lock, true);
1051 
1052 	// fill a port_info struct with info
1053 	fill_port_info(port, info, size);
1054 	return B_OK;
1055 }
1056 
1057 
1058 status_t
1059 _get_next_port_info(team_id teamID, int32* _cookie, struct port_info* info,
1060 	size_t size)
1061 {
1062 	TRACE(("get_next_port_info(team = %ld)\n", teamID));
1063 
1064 	if (info == NULL || size != sizeof(port_info) || _cookie == NULL
1065 		|| teamID < 0) {
1066 		return B_BAD_VALUE;
1067 	}
1068 	if (!sPortsActive)
1069 		return B_BAD_PORT_ID;
1070 
1071 	Team* team = Team::Get(teamID);
1072 	if (team == NULL)
1073 		return B_BAD_TEAM_ID;
1074 	BReference<Team> teamReference(team, true);
1075 
1076 	// iterate through the team's port list
1077 	MutexLocker portsLocker(sPortsLock);
1078 
1079 	int32 stopIndex = *_cookie;
1080 	int32 index = 0;
1081 
1082 	Port* port = (Port*)list_get_first_item(&team->port_list);
1083 	while (port != NULL) {
1084 		if (!is_port_closed(port)) {
1085 			if (index == stopIndex)
1086 				break;
1087 			index++;
1088 		}
1089 
1090 		port = (Port*)list_get_next_item(&team->port_list, port);
1091 	}
1092 
1093 	if (port == NULL)
1094 		return B_BAD_PORT_ID;
1095 
1096 	// fill in the port info
1097 	MutexLocker locker(port->lock);
1098 	portsLocker.Unlock();
1099 	fill_port_info(port, info, size);
1100 
1101 	*_cookie = stopIndex + 1;
1102 	return B_OK;
1103 }
1104 
1105 
1106 ssize_t
1107 port_buffer_size(port_id id)
1108 {
1109 	return port_buffer_size_etc(id, 0, 0);
1110 }
1111 
1112 
1113 ssize_t
1114 port_buffer_size_etc(port_id id, uint32 flags, bigtime_t timeout)
1115 {
1116 	port_message_info info;
1117 	status_t error = get_port_message_info_etc(id, &info, flags, timeout);
1118 	return error != B_OK ? error : info.size;
1119 }
1120 
1121 
1122 status_t
1123 _get_port_message_info_etc(port_id id, port_message_info* info,
1124 	size_t infoSize, uint32 flags, bigtime_t timeout)
1125 {
1126 	if (info == NULL || infoSize != sizeof(port_message_info))
1127 		return B_BAD_VALUE;
1128 	if (!sPortsActive || id < 0)
1129 		return B_BAD_PORT_ID;
1130 
1131 	flags &= B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT | B_RELATIVE_TIMEOUT
1132 		| B_ABSOLUTE_TIMEOUT;
1133 
1134 	// get the port
1135 	Port* port = get_locked_port(id);
1136 	if (port == NULL)
1137 		return B_BAD_PORT_ID;
1138 	MutexLocker locker(port->lock, true);
1139 
1140 	if (is_port_closed(port) && port->messages.IsEmpty()) {
1141 		T(Info(port, 0, B_BAD_PORT_ID));
1142 		TRACE(("_get_port_message_info_etc(): closed port %ld\n", id));
1143 		return B_BAD_PORT_ID;
1144 	}
1145 
1146 	while (port->read_count == 0) {
1147 		// We need to wait for a message to appear
1148 		if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0)
1149 			return B_WOULD_BLOCK;
1150 
1151 		ConditionVariableEntry entry;
1152 		port->read_condition.Add(&entry);
1153 
1154 		locker.Unlock();
1155 
1156 		// block if no message, or, if B_TIMEOUT flag set, block with timeout
1157 		status_t status = entry.Wait(flags, timeout);
1158 
1159 		if (status != B_OK) {
1160 			T(Info(port, 0, status));
1161 			return status;
1162 		}
1163 
1164 		// re-lock
1165 		Port* newPort = get_locked_port(id);
1166 		if (newPort == NULL) {
1167 			T(Info(id, 0, 0, 0, B_BAD_PORT_ID));
1168 			return B_BAD_PORT_ID;
1169 		}
1170 		locker.SetTo(newPort->lock, true);
1171 
1172 		if (newPort != port
1173 			|| (is_port_closed(port) && port->messages.IsEmpty())) {
1174 			// the port is no longer there
1175 			T(Info(id, 0, 0, 0, B_BAD_PORT_ID));
1176 			return B_BAD_PORT_ID;
1177 		}
1178 	}
1179 
1180 	// determine tail & get the length of the message
1181 	port_message* message = port->messages.Head();
1182 	if (message == NULL) {
1183 		panic("port %ld: no messages found\n", port->id);
1184 		return B_ERROR;
1185 	}
1186 
1187 	info->size = message->size;
1188 	info->sender = message->sender;
1189 	info->sender_group = message->sender_group;
1190 	info->sender_team = message->sender_team;
1191 
1192 	T(Info(id, id->read_count, id->write_count, message->code, B_OK));
1193 
1194 	// notify next one, as we haven't read from the port
1195 	port->read_condition.NotifyOne();
1196 
1197 	return B_OK;
1198 }
1199 
1200 
1201 ssize_t
1202 port_count(port_id id)
1203 {
1204 	if (!sPortsActive || id < 0)
1205 		return B_BAD_PORT_ID;
1206 
1207 	// get the port
1208 	Port* port = get_locked_port(id);
1209 	if (port == NULL) {
1210 		TRACE(("port_count: invalid port_id %ld\n", id));
1211 		return B_BAD_PORT_ID;
1212 	}
1213 	MutexLocker locker(port->lock, true);
1214 
1215 	// return count of messages
1216 	return port->read_count;
1217 }
1218 
1219 
1220 ssize_t
1221 read_port(port_id port, int32* msgCode, void* buffer, size_t bufferSize)
1222 {
1223 	return read_port_etc(port, msgCode, buffer, bufferSize, 0, 0);
1224 }
1225 
1226 
1227 ssize_t
1228 read_port_etc(port_id id, int32* _code, void* buffer, size_t bufferSize,
1229 	uint32 flags, bigtime_t timeout)
1230 {
1231 	if (!sPortsActive || id < 0)
1232 		return B_BAD_PORT_ID;
1233 	if ((buffer == NULL && bufferSize > 0) || timeout < 0)
1234 		return B_BAD_VALUE;
1235 
1236 	bool userCopy = (flags & PORT_FLAG_USE_USER_MEMCPY) != 0;
1237 	bool peekOnly = !userCopy && (flags & B_PEEK_PORT_MESSAGE) != 0;
1238 		// TODO: we could allow peeking for user apps now
1239 
1240 	flags &= B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT | B_RELATIVE_TIMEOUT
1241 		| B_ABSOLUTE_TIMEOUT;
1242 
1243 	// get the port
1244 	Port* port = get_locked_port(id);
1245 	if (port == NULL)
1246 		return B_BAD_PORT_ID;
1247 	MutexLocker locker(port->lock, true);
1248 
1249 	if (is_port_closed(port) && port->messages.IsEmpty()) {
1250 		T(Read(port, 0, B_BAD_PORT_ID));
1251 		TRACE(("read_port_etc(): closed port %ld\n", id));
1252 		return B_BAD_PORT_ID;
1253 	}
1254 
1255 	while (port->read_count == 0) {
1256 		if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0)
1257 			return B_WOULD_BLOCK;
1258 
1259 		// We need to wait for a message to appear
1260 		ConditionVariableEntry entry;
1261 		port->read_condition.Add(&entry);
1262 
1263 		locker.Unlock();
1264 
1265 		// block if no message, or, if B_TIMEOUT flag set, block with timeout
1266 		status_t status = entry.Wait(flags, timeout);
1267 
1268 		// re-lock
1269 		Port* newPort = get_locked_port(id);
1270 		if (newPort == NULL) {
1271 			T(Read(id, 0, 0, 0, B_BAD_PORT_ID));
1272 			return B_BAD_PORT_ID;
1273 		}
1274 		locker.SetTo(newPort->lock, true);
1275 
1276 		if (newPort != port
1277 			|| (is_port_closed(port) && port->messages.IsEmpty())) {
1278 			// the port is no longer there
1279 			T(Read(id, 0, 0, 0, B_BAD_PORT_ID));
1280 			return B_BAD_PORT_ID;
1281 		}
1282 
1283 		if (status != B_OK) {
1284 			T(Read(port, 0, status));
1285 			return status;
1286 		}
1287 	}
1288 
1289 	// determine tail & get the length of the message
1290 	port_message* message = port->messages.Head();
1291 	if (message == NULL) {
1292 		panic("port %ld: no messages found\n", port->id);
1293 		return B_ERROR;
1294 	}
1295 
1296 	if (peekOnly) {
1297 		size_t size = copy_port_message(message, _code, buffer, bufferSize,
1298 			userCopy);
1299 
1300 		T(Read(port, message->code, size));
1301 
1302 		port->read_condition.NotifyOne();
1303 			// we only peeked, but didn't grab the message
1304 		return size;
1305 	}
1306 
1307 	port->messages.RemoveHead();
1308 	port->total_count++;
1309 	port->write_count++;
1310 	port->read_count--;
1311 
1312 	notify_port_select_events(port, B_EVENT_WRITE);
1313 	port->write_condition.NotifyOne();
1314 		// make one spot in queue available again for write
1315 
1316 	T(Read(id, port->read_count, port->write_count, message->code,
1317 		min_c(bufferSize, message->size)));
1318 
1319 	locker.Unlock();
1320 
1321 	size_t size = copy_port_message(message, _code, buffer, bufferSize,
1322 		userCopy);
1323 
1324 	put_port_message(message);
1325 	return size;
1326 }
1327 
1328 
1329 status_t
1330 write_port(port_id id, int32 msgCode, const void* buffer, size_t bufferSize)
1331 {
1332 	iovec vec = { (void*)buffer, bufferSize };
1333 
1334 	return writev_port_etc(id, msgCode, &vec, 1, bufferSize, 0, 0);
1335 }
1336 
1337 
1338 status_t
1339 write_port_etc(port_id id, int32 msgCode, const void* buffer,
1340 	size_t bufferSize, uint32 flags, bigtime_t timeout)
1341 {
1342 	iovec vec = { (void*)buffer, bufferSize };
1343 
1344 	return writev_port_etc(id, msgCode, &vec, 1, bufferSize, flags, timeout);
1345 }
1346 
1347 
1348 status_t
1349 writev_port_etc(port_id id, int32 msgCode, const iovec* msgVecs,
1350 	size_t vecCount, size_t bufferSize, uint32 flags, bigtime_t timeout)
1351 {
1352 	if (!sPortsActive || id < 0)
1353 		return B_BAD_PORT_ID;
1354 	if (bufferSize > PORT_MAX_MESSAGE_SIZE)
1355 		return B_BAD_VALUE;
1356 
1357 	// mask irrelevant flags (for acquire_sem() usage)
1358 	flags &= B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT | B_RELATIVE_TIMEOUT
1359 		| B_ABSOLUTE_TIMEOUT;
1360 	if ((flags & B_RELATIVE_TIMEOUT) != 0
1361 		&& timeout != B_INFINITE_TIMEOUT && timeout > 0) {
1362 		// Make the timeout absolute, since we have more than one step where
1363 		// we might have to wait
1364 		flags = (flags & ~B_RELATIVE_TIMEOUT) | B_ABSOLUTE_TIMEOUT;
1365 		timeout += system_time();
1366 	}
1367 
1368 	bool userCopy = (flags & PORT_FLAG_USE_USER_MEMCPY) > 0;
1369 
1370 	status_t status;
1371 	port_message* message = NULL;
1372 
1373 	// get the port
1374 	Port* port = get_locked_port(id);
1375 	if (port == NULL) {
1376 		TRACE(("write_port_etc: invalid port_id %ld\n", id));
1377 		return B_BAD_PORT_ID;
1378 	}
1379 	MutexLocker locker(port->lock, true);
1380 
1381 	if (is_port_closed(port)) {
1382 		TRACE(("write_port_etc: port %ld closed\n", id));
1383 		return B_BAD_PORT_ID;
1384 	}
1385 
1386 	if (port->write_count <= 0) {
1387 		if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0)
1388 			return B_WOULD_BLOCK;
1389 
1390 		port->write_count--;
1391 
1392 		// We need to block in order to wait for a free message slot
1393 		ConditionVariableEntry entry;
1394 		port->write_condition.Add(&entry);
1395 
1396 		locker.Unlock();
1397 
1398 		status = entry.Wait(flags, timeout);
1399 
1400 		// re-lock
1401 		Port* newPort = get_locked_port(id);
1402 		if (newPort == NULL) {
1403 			T(Write(id, 0, 0, 0, 0, B_BAD_PORT_ID));
1404 			return B_BAD_PORT_ID;
1405 		}
1406 		locker.SetTo(newPort->lock, true);
1407 
1408 		if (newPort != port || is_port_closed(port)) {
1409 			// the port is no longer there
1410 			T(Write(id, 0, 0, 0, 0, B_BAD_PORT_ID));
1411 			return B_BAD_PORT_ID;
1412 		}
1413 
1414 		if (status != B_OK)
1415 			goto error;
1416 	} else
1417 		port->write_count--;
1418 
1419 	status = get_port_message(msgCode, bufferSize, flags, timeout,
1420 		&message, *port);
1421 	if (status != B_OK) {
1422 		if (status == B_BAD_PORT_ID) {
1423 			// the port had to be unlocked and is now no longer there
1424 			T(Write(id, 0, 0, 0, 0, B_BAD_PORT_ID));
1425 			return B_BAD_PORT_ID;
1426 		}
1427 
1428 		goto error;
1429 	}
1430 
1431 	// sender credentials
1432 	message->sender = geteuid();
1433 	message->sender_group = getegid();
1434 	message->sender_team = team_get_current_team_id();
1435 
1436 	if (bufferSize > 0) {
1437 		size_t offset = 0;
1438 		for (uint32 i = 0; i < vecCount; i++) {
1439 			size_t bytes = msgVecs[i].iov_len;
1440 			if (bytes > bufferSize)
1441 				bytes = bufferSize;
1442 
1443 			if (userCopy) {
1444 				status_t status = user_memcpy(message->buffer + offset,
1445 					msgVecs[i].iov_base, bytes);
1446 				if (status != B_OK) {
1447 					put_port_message(message);
1448 					goto error;
1449 				}
1450 			} else
1451 				memcpy(message->buffer + offset, msgVecs[i].iov_base, bytes);
1452 
1453 			bufferSize -= bytes;
1454 			if (bufferSize == 0)
1455 				break;
1456 
1457 			offset += bytes;
1458 		}
1459 	}
1460 
1461 	port->messages.Add(message);
1462 	port->read_count++;
1463 
1464 	T(Write(id, port->read_count, port->write_count, message->code,
1465 		message->size, B_OK));
1466 
1467 	notify_port_select_events(port, B_EVENT_READ);
1468 	port->read_condition.NotifyOne();
1469 	return B_OK;
1470 
1471 error:
1472 	// Give up our slot in the queue again, and let someone else
1473 	// try and fail
1474 	T(Write(id, port->read_count, port->write_count, 0, 0, status));
1475 	port->write_count++;
1476 	notify_port_select_events(port, B_EVENT_WRITE);
1477 	port->write_condition.NotifyOne();
1478 
1479 	return status;
1480 }
1481 
1482 
1483 status_t
1484 set_port_owner(port_id id, team_id newTeamID)
1485 {
1486 	TRACE(("set_port_owner(id = %ld, team = %ld)\n", id, newTeamID));
1487 
1488 	if (id < 0)
1489 		return B_BAD_PORT_ID;
1490 
1491 	// get the new team
1492 	Team* team = Team::Get(newTeamID);
1493 	if (team == NULL)
1494 		return B_BAD_TEAM_ID;
1495 	BReference<Team> teamReference(team, true);
1496 
1497 	// get the port
1498 	MutexLocker portsLocker(sPortsLock);
1499 	Port* port = sPorts.Lookup(id);
1500 	if (port == NULL) {
1501 		TRACE(("set_port_owner: invalid port_id %ld\n", id));
1502 		return B_BAD_PORT_ID;
1503 	}
1504 	MutexLocker locker(port->lock);
1505 
1506 	// transfer ownership to other team
1507 	if (team->id != port->owner) {
1508 		list_remove_link(&port->team_link);
1509 		list_add_item(&team->port_list, &port->team_link);
1510 		port->owner = team->id;
1511 	}
1512 
1513 	T(OwnerChange(port, team->id, B_OK));
1514 	return B_OK;
1515 }
1516 
1517 
1518 //	#pragma mark - syscalls
1519 
1520 
1521 port_id
1522 _user_create_port(int32 queueLength, const char *userName)
1523 {
1524 	char name[B_OS_NAME_LENGTH];
1525 
1526 	if (userName == NULL)
1527 		return create_port(queueLength, NULL);
1528 
1529 	if (!IS_USER_ADDRESS(userName)
1530 		|| user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK)
1531 		return B_BAD_ADDRESS;
1532 
1533 	return create_port(queueLength, name);
1534 }
1535 
1536 
1537 status_t
1538 _user_close_port(port_id id)
1539 {
1540 	return close_port(id);
1541 }
1542 
1543 
1544 status_t
1545 _user_delete_port(port_id id)
1546 {
1547 	return delete_port(id);
1548 }
1549 
1550 
1551 port_id
1552 _user_find_port(const char *userName)
1553 {
1554 	char name[B_OS_NAME_LENGTH];
1555 
1556 	if (userName == NULL)
1557 		return B_BAD_VALUE;
1558 	if (!IS_USER_ADDRESS(userName)
1559 		|| user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK)
1560 		return B_BAD_ADDRESS;
1561 
1562 	return find_port(name);
1563 }
1564 
1565 
1566 status_t
1567 _user_get_port_info(port_id id, struct port_info *userInfo)
1568 {
1569 	struct port_info info;
1570 	status_t status;
1571 
1572 	if (userInfo == NULL)
1573 		return B_BAD_VALUE;
1574 	if (!IS_USER_ADDRESS(userInfo))
1575 		return B_BAD_ADDRESS;
1576 
1577 	status = get_port_info(id, &info);
1578 
1579 	// copy back to user space
1580 	if (status == B_OK
1581 		&& user_memcpy(userInfo, &info, sizeof(struct port_info)) < B_OK)
1582 		return B_BAD_ADDRESS;
1583 
1584 	return status;
1585 }
1586 
1587 
1588 status_t
1589 _user_get_next_port_info(team_id team, int32 *userCookie,
1590 	struct port_info *userInfo)
1591 {
1592 	struct port_info info;
1593 	status_t status;
1594 	int32 cookie;
1595 
1596 	if (userCookie == NULL || userInfo == NULL)
1597 		return B_BAD_VALUE;
1598 	if (!IS_USER_ADDRESS(userCookie) || !IS_USER_ADDRESS(userInfo)
1599 		|| user_memcpy(&cookie, userCookie, sizeof(int32)) < B_OK)
1600 		return B_BAD_ADDRESS;
1601 
1602 	status = get_next_port_info(team, &cookie, &info);
1603 
1604 	// copy back to user space
1605 	if (user_memcpy(userCookie, &cookie, sizeof(int32)) < B_OK
1606 		|| (status == B_OK && user_memcpy(userInfo, &info,
1607 				sizeof(struct port_info)) < B_OK))
1608 		return B_BAD_ADDRESS;
1609 
1610 	return status;
1611 }
1612 
1613 
1614 ssize_t
1615 _user_port_buffer_size_etc(port_id port, uint32 flags, bigtime_t timeout)
1616 {
1617 	syscall_restart_handle_timeout_pre(flags, timeout);
1618 
1619 	status_t status = port_buffer_size_etc(port, flags | B_CAN_INTERRUPT,
1620 		timeout);
1621 
1622 	return syscall_restart_handle_timeout_post(status, timeout);
1623 }
1624 
1625 
1626 ssize_t
1627 _user_port_count(port_id port)
1628 {
1629 	return port_count(port);
1630 }
1631 
1632 
1633 status_t
1634 _user_set_port_owner(port_id port, team_id team)
1635 {
1636 	return set_port_owner(port, team);
1637 }
1638 
1639 
1640 ssize_t
1641 _user_read_port_etc(port_id port, int32 *userCode, void *userBuffer,
1642 	size_t bufferSize, uint32 flags, bigtime_t timeout)
1643 {
1644 	int32 messageCode;
1645 	ssize_t	bytesRead;
1646 
1647 	syscall_restart_handle_timeout_pre(flags, timeout);
1648 
1649 	if (userBuffer == NULL && bufferSize != 0)
1650 		return B_BAD_VALUE;
1651 	if ((userCode != NULL && !IS_USER_ADDRESS(userCode))
1652 		|| (userBuffer != NULL && !IS_USER_ADDRESS(userBuffer)))
1653 		return B_BAD_ADDRESS;
1654 
1655 	bytesRead = read_port_etc(port, &messageCode, userBuffer, bufferSize,
1656 		flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT, timeout);
1657 
1658 	if (bytesRead >= 0 && userCode != NULL
1659 		&& user_memcpy(userCode, &messageCode, sizeof(int32)) < B_OK)
1660 		return B_BAD_ADDRESS;
1661 
1662 	return syscall_restart_handle_timeout_post(bytesRead, timeout);
1663 }
1664 
1665 
1666 status_t
1667 _user_write_port_etc(port_id port, int32 messageCode, const void *userBuffer,
1668 	size_t bufferSize, uint32 flags, bigtime_t timeout)
1669 {
1670 	iovec vec = { (void *)userBuffer, bufferSize };
1671 
1672 	syscall_restart_handle_timeout_pre(flags, timeout);
1673 
1674 	if (userBuffer == NULL && bufferSize != 0)
1675 		return B_BAD_VALUE;
1676 	if (userBuffer != NULL && !IS_USER_ADDRESS(userBuffer))
1677 		return B_BAD_ADDRESS;
1678 
1679 	status_t status = writev_port_etc(port, messageCode, &vec, 1, bufferSize,
1680 		flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT, timeout);
1681 
1682 	return syscall_restart_handle_timeout_post(status, timeout);
1683 }
1684 
1685 
1686 status_t
1687 _user_writev_port_etc(port_id port, int32 messageCode, const iovec *userVecs,
1688 	size_t vecCount, size_t bufferSize, uint32 flags, bigtime_t timeout)
1689 {
1690 	syscall_restart_handle_timeout_pre(flags, timeout);
1691 
1692 	if (userVecs == NULL && bufferSize != 0)
1693 		return B_BAD_VALUE;
1694 	if (userVecs != NULL && !IS_USER_ADDRESS(userVecs))
1695 		return B_BAD_ADDRESS;
1696 
1697 	iovec *vecs = NULL;
1698 	if (userVecs && vecCount != 0) {
1699 		vecs = (iovec*)malloc(sizeof(iovec) * vecCount);
1700 		if (vecs == NULL)
1701 			return B_NO_MEMORY;
1702 
1703 		if (user_memcpy(vecs, userVecs, sizeof(iovec) * vecCount) < B_OK) {
1704 			free(vecs);
1705 			return B_BAD_ADDRESS;
1706 		}
1707 	}
1708 
1709 	status_t status = writev_port_etc(port, messageCode, vecs, vecCount,
1710 		bufferSize, flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT,
1711 		timeout);
1712 
1713 	free(vecs);
1714 	return syscall_restart_handle_timeout_post(status, timeout);
1715 }
1716 
1717 
1718 status_t
1719 _user_get_port_message_info_etc(port_id port, port_message_info *userInfo,
1720 	size_t infoSize, uint32 flags, bigtime_t timeout)
1721 {
1722 	if (userInfo == NULL || infoSize != sizeof(port_message_info))
1723 		return B_BAD_VALUE;
1724 
1725 	syscall_restart_handle_timeout_pre(flags, timeout);
1726 
1727 	port_message_info info;
1728 	status_t error = _get_port_message_info_etc(port, &info, sizeof(info),
1729 		flags | B_CAN_INTERRUPT, timeout);
1730 
1731 	// copy info to userland
1732 	if (error == B_OK && (!IS_USER_ADDRESS(userInfo)
1733 			|| user_memcpy(userInfo, &info, sizeof(info)) != B_OK)) {
1734 		error = B_BAD_ADDRESS;
1735 	}
1736 
1737 	return syscall_restart_handle_timeout_post(error, timeout);
1738 }
1739