xref: /haiku/src/system/kernel/port.cpp (revision 8d2bf6953e851d431fc67de1bc970c40afa79e9f)
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[128];
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 %8" B_PRId32 " %4" B_PRId32 " %9" B_PRIu32 " %9" B_PRId32
407 			" %8" B_PRId32 " %6" B_PRId32 "  %s\n", port, port->id,
408 			port->capacity, port->read_count, port->write_count,
409 			port->total_count, port->owner, port->lock.name);
410 	}
411 
412 	return 0;
413 }
414 
415 
416 static void
417 _dump_port_info(Port* port)
418 {
419 	kprintf("PORT: %p\n", port);
420 	kprintf(" id:              %" B_PRId32 "\n", port->id);
421 	kprintf(" name:            \"%s\"\n", port->lock.name);
422 	kprintf(" owner:           %" B_PRId32 "\n", port->owner);
423 	kprintf(" capacity:        %" B_PRId32 "\n", port->capacity);
424 	kprintf(" read_count:      %" B_PRIu32 "\n", port->read_count);
425 	kprintf(" write_count:     %" B_PRId32 "\n", port->write_count);
426 	kprintf(" total count:     %" B_PRId32 "\n", port->total_count);
427 
428 	if (!port->messages.IsEmpty()) {
429 		kprintf("messages:\n");
430 
431 		MessageList::Iterator iterator = port->messages.GetIterator();
432 		while (port_message* message = iterator.Next()) {
433 			kprintf(" %p  %08" B_PRIx32 "  %ld\n", message, message->code, message->size);
434 		}
435 	}
436 
437 	set_debug_variable("_port", (addr_t)port);
438 	set_debug_variable("_portID", port->id);
439 	set_debug_variable("_owner", port->owner);
440 }
441 
442 
443 static int
444 dump_port_info(int argc, char** argv)
445 {
446 	ConditionVariable* condition = NULL;
447 	const char* name = NULL;
448 
449 	if (argc < 2) {
450 		print_debugger_command_usage(argv[0]);
451 		return 0;
452 	}
453 
454 	if (argc > 2) {
455 		if (!strcmp(argv[1], "address")) {
456 			_dump_port_info((Port*)parse_expression(argv[2]));
457 			return 0;
458 		} else if (!strcmp(argv[1], "condition"))
459 			condition = (ConditionVariable*)parse_expression(argv[2]);
460 		else if (!strcmp(argv[1], "name"))
461 			name = argv[2];
462 	} else if (parse_expression(argv[1]) > 0) {
463 		// if the argument looks like a number, treat it as such
464 		int32 num = parse_expression(argv[1]);
465 		Port* port = sPorts.Lookup(num);
466 		if (port == NULL) {
467 			kprintf("port %" B_PRId32 " (%#" B_PRIx32 ") doesn't exist!\n",
468 				num, num);
469 			return 0;
470 		}
471 		_dump_port_info(port);
472 		return 0;
473 	} else
474 		name = argv[1];
475 
476 	// walk through the ports list, trying to match name
477 	for (PortHashTable::Iterator it = sPorts.GetIterator();
478 		Port* port = it.Next();) {
479 		if ((name != NULL && port->lock.name != NULL
480 				&& !strcmp(name, port->lock.name))
481 			|| (condition != NULL && (&port->read_condition == condition
482 				|| &port->write_condition == condition))) {
483 			_dump_port_info(port);
484 			return 0;
485 		}
486 	}
487 
488 	return 0;
489 }
490 
491 
492 /*!	Notifies the port's select events.
493 	The port must be locked.
494 */
495 static void
496 notify_port_select_events(Port* port, uint16 events)
497 {
498 	if (port->select_infos)
499 		notify_select_events_list(port->select_infos, events);
500 }
501 
502 
503 static Port*
504 get_locked_port(port_id id)
505 {
506 	MutexLocker portsLocker(sPortsLock);
507 
508 	Port* port = sPorts.Lookup(id);
509 	if (port != NULL)
510 		mutex_lock(&port->lock);
511 	return port;
512 }
513 
514 
515 /*!	You need to own the port's lock when calling this function */
516 static inline bool
517 is_port_closed(Port* port)
518 {
519 	return port->capacity == 0;
520 }
521 
522 
523 static void
524 put_port_message(port_message* message)
525 {
526 	size_t size = sizeof(port_message) + message->size;
527 	heap_free(sPortAllocator, message);
528 
529 	MutexLocker quotaLocker(sPortQuotaLock);
530 	sTotalSpaceInUse -= size;
531 	if (sWaitingForSpace > 0)
532 		sNoSpaceCondition.NotifyAll();
533 }
534 
535 
536 static status_t
537 get_port_message(int32 code, size_t bufferSize, uint32 flags, bigtime_t timeout,
538 	port_message** _message, Port& port)
539 {
540 	size_t size = sizeof(port_message) + bufferSize;
541 	bool needToWait = false;
542 
543 	MutexLocker quotaLocker(sPortQuotaLock);
544 
545 	while (true) {
546 		while (sTotalSpaceInUse + size > kTotalSpaceLimit || needToWait) {
547 			// TODO: add per team limit
548 			// We are not allowed to create another heap area, as our
549 			// space limit has been reached - just wait until we get
550 			// some free space again.
551 
552 			// TODO: we don't want to wait - but does that also mean we
553 			// shouldn't wait for the area creation?
554 			if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0)
555 				return B_WOULD_BLOCK;
556 
557 			ConditionVariableEntry entry;
558 			sNoSpaceCondition.Add(&entry);
559 
560 			sWaitingForSpace++;
561 			quotaLocker.Unlock();
562 
563 			port_id portID = port.id;
564 			mutex_unlock(&port.lock);
565 
566 			status_t status = entry.Wait(flags, timeout);
567 
568 			// re-lock the port and the quota
569 			Port* newPort = get_locked_port(portID);
570 			quotaLocker.Lock();
571 			sWaitingForSpace--;
572 
573 			if (newPort != &port || is_port_closed(&port)) {
574 				// the port is no longer usable
575 				return B_BAD_PORT_ID;
576 			}
577 
578 			if (status == B_TIMED_OUT)
579 				return B_TIMED_OUT;
580 
581 			needToWait = false;
582 			continue;
583 		}
584 
585 		int32 areaChangeCounter = sAreaChangeCounter;
586 		sTotalSpaceInUse += size;
587 		quotaLocker.Unlock();
588 
589 		// Quota is fulfilled, try to allocate the buffer
590 
591 		port_message* message
592 			= (port_message*)heap_memalign(sPortAllocator, 0, size);
593 		if (message != NULL) {
594 			message->code = code;
595 			message->size = bufferSize;
596 
597 			*_message = message;
598 			return B_OK;
599 		}
600 
601 		quotaLocker.Lock();
602 
603 		// We weren't able to allocate and we'll start over, including
604 		// re-acquireing the quota, so we remove our size from the in-use
605 		// counter again.
606 		sTotalSpaceInUse -= size;
607 
608 		if (areaChangeCounter != sAreaChangeCounter) {
609 			// There was already an area added since we tried allocating,
610 			// start over.
611 			continue;
612 		}
613 
614 		// Create a new area for the heap to use
615 
616 		addr_t base;
617 		area_id area = create_area("port grown buffer", (void**)&base,
618 			B_ANY_KERNEL_ADDRESS, kBufferGrowRate, B_NO_LOCK,
619 			B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
620 		if (area < 0) {
621 			// We'll have to get by with what we have, so wait for someone
622 			// to free a message instead. We enforce waiting so that we don't
623 			// try to create a new area over and over.
624 			needToWait = true;
625 			continue;
626 		}
627 
628 		heap_add_area(sPortAllocator, area, base, kBufferGrowRate);
629 
630 		sAreaChangeCounter++;
631 		if (sWaitingForSpace > 0)
632 			sNoSpaceCondition.NotifyAll();
633 	}
634 }
635 
636 
637 /*!	Fills the port_info structure with information from the specified
638 	port.
639 	The port's lock must be held when called.
640 */
641 static void
642 fill_port_info(Port* port, port_info* info, size_t size)
643 {
644 	info->port = port->id;
645 	info->team = port->owner;
646 	info->capacity = port->capacity;
647 
648 	info->queue_count = port->read_count;
649 	info->total_count = port->total_count;
650 
651 	strlcpy(info->name, port->lock.name, B_OS_NAME_LENGTH);
652 }
653 
654 
655 static ssize_t
656 copy_port_message(port_message* message, int32* _code, void* buffer,
657 	size_t bufferSize, bool userCopy)
658 {
659 	// check output buffer size
660 	size_t size = min_c(bufferSize, message->size);
661 
662 	// copy message
663 	if (_code != NULL)
664 		*_code = message->code;
665 
666 	if (size > 0) {
667 		if (userCopy) {
668 			status_t status = user_memcpy(buffer, message->buffer, size);
669 			if (status != B_OK)
670 				return status;
671 		} else
672 			memcpy(buffer, message->buffer, size);
673 	}
674 
675 	return size;
676 }
677 
678 
679 static void
680 uninit_port_locked(Port* port)
681 {
682 	notify_port_select_events(port, B_EVENT_INVALID);
683 	port->select_infos = NULL;
684 
685 	// Release the threads that were blocking on this port.
686 	// read_port() will see the B_BAD_PORT_ID return value, and act accordingly
687 	port->read_condition.NotifyAll(false, B_BAD_PORT_ID);
688 	port->write_condition.NotifyAll(false, B_BAD_PORT_ID);
689 	sNotificationService.Notify(PORT_REMOVED, port->id);
690 }
691 
692 
693 //	#pragma mark - private kernel API
694 
695 
696 /*! This function deletes all the ports that are owned by the passed team.
697 */
698 void
699 delete_owned_ports(Team* team)
700 {
701 	TRACE(("delete_owned_ports(owner = %ld)\n", team->id));
702 
703 	MutexLocker portsLocker(sPortsLock);
704 
705 	// move the ports from the team's port list to a local list
706 	struct list queue;
707 	list_move_to_list(&team->port_list, &queue);
708 
709 	// iterate through the list or ports, remove them from the hash table and
710 	// uninitialize them
711 	Port* port = (Port*)list_get_first_item(&queue);
712 	while (port != NULL) {
713 		MutexLocker locker(port->lock);
714 		sPorts.Remove(port);
715 		uninit_port_locked(port);
716 		sUsedPorts--;
717 
718 		port = (Port*)list_get_next_item(&queue, port);
719 	}
720 
721 	portsLocker.Unlock();
722 
723 	// delete the ports
724 	while (Port* port = (Port*)list_remove_head_item(&queue))
725 		delete port;
726 }
727 
728 
729 int32
730 port_max_ports(void)
731 {
732 	return sMaxPorts;
733 }
734 
735 
736 int32
737 port_used_ports(void)
738 {
739 	return sUsedPorts;
740 }
741 
742 
743 status_t
744 port_init(kernel_args *args)
745 {
746 	// initialize ports table
747 	new(&sPorts) PortHashTable;
748 	if (sPorts.Init() != B_OK) {
749 		panic("Failed to init port hash table!");
750 		return B_NO_MEMORY;
751 	}
752 
753 	addr_t base;
754 	if (create_area("port heap", (void**)&base, B_ANY_KERNEL_ADDRESS,
755 			kInitialPortBufferSize, B_NO_LOCK,
756 			B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA) < 0) {
757 			// TODO: Since port_init() is invoked before the boot partition is
758 			// mounted, the underlying VMAnonymousCache cannot commit swap space
759 			// upon creation and thus the pages aren't swappable after all. This
760 			// makes the area essentially B_LAZY_LOCK with additional overhead.
761 		panic("unable to allocate port area!\n");
762 		return B_ERROR;
763 	}
764 
765 	static const heap_class kBufferHeapClass = { "port heap", 100,
766 		PORT_MAX_MESSAGE_SIZE + sizeof(port_message), 2 * 1024,
767 		sizeof(port_message), 4, 2, 24 };
768 	sPortAllocator = heap_create_allocator("port buffer", base,
769 		kInitialPortBufferSize, &kBufferHeapClass, true);
770 	if (sPortAllocator == NULL) {
771 		panic("unable to create port heap");
772 		return B_NO_MEMORY;
773 	}
774 
775 	sNoSpaceCondition.Init(&sPorts, "port space");
776 
777 	// add debugger commands
778 	add_debugger_command_etc("ports", &dump_port_list,
779 		"Dump a list of all active ports (for team, with name, etc.)",
780 		"[ ([ \"team\" | \"owner\" ] <team>) | (\"name\" <name>) ]\n"
781 		"Prints a list of all active ports meeting the given\n"
782 		"requirement. If no argument is given, all ports are listed.\n"
783 		"  <team>             - The team owning the ports.\n"
784 		"  <name>             - Part of the name of the ports.\n", 0);
785 	add_debugger_command_etc("port", &dump_port_info,
786 		"Dump info about a particular port",
787 		"(<id> | [ \"address\" ] <address>) | ([ \"name\" ] <name>) "
788 			"| (\"condition\" <address>)\n"
789 		"Prints info about the specified port.\n"
790 		"  <address>   - Pointer to the port structure.\n"
791 		"  <name>      - Name of the port.\n"
792 		"  <condition> - address of the port's read or write condition.\n", 0);
793 
794 	new(&sNotificationService) PortNotificationService();
795 	sNotificationService.Register();
796 	sPortsActive = true;
797 	return B_OK;
798 }
799 
800 
801 //	#pragma mark - public kernel API
802 
803 
804 port_id
805 create_port(int32 queueLength, const char* name)
806 {
807 	TRACE(("create_port(queueLength = %ld, name = \"%s\")\n", queueLength,
808 		name));
809 
810 	if (!sPortsActive) {
811 		panic("ports used too early!\n");
812 		return B_BAD_PORT_ID;
813 	}
814 	if (queueLength < 1 || queueLength > MAX_QUEUE_LENGTH)
815 		return B_BAD_VALUE;
816 
817 	Team* team = thread_get_current_thread()->team;
818 	if (team == NULL)
819 		return B_BAD_TEAM_ID;
820 
821 	// check & dup name
822 	char* nameBuffer = strdup(name != NULL ? name : "unnamed port");
823 	if (nameBuffer == NULL)
824 		return B_NO_MEMORY;
825 
826 	// create a port
827 	Port* port = new(std::nothrow) Port(team_get_current_team_id(), queueLength,
828 		nameBuffer);
829 	if (port == NULL) {
830 		free(nameBuffer);
831 		return B_NO_MEMORY;
832 	}
833 	ObjectDeleter<Port> portDeleter(port);
834 
835 	MutexLocker locker(sPortsLock);
836 
837 	// check the ports limit
838 	if (sUsedPorts >= sMaxPorts)
839 		return B_NO_MORE_PORTS;
840 
841 	sUsedPorts++;
842 
843 	// allocate a port ID
844 	do {
845 		port->id = sNextPortID++;
846 
847 		// handle integer overflow
848 		if (sNextPortID < 0)
849 			sNextPortID = 1;
850 	} while (sPorts.Lookup(port->id) != NULL);
851 
852 	// insert port in table and team list
853 	sPorts.Insert(port);
854 	list_add_item(&team->port_list, &port->team_link);
855 	portDeleter.Detach();
856 
857 	// tracing, notifications, etc.
858 	T(Create(port));
859 
860 	port_id id = port->id;
861 
862 	locker.Unlock();
863 
864 	TRACE(("create_port() done: port created %ld\n", id));
865 
866 	sNotificationService.Notify(PORT_ADDED, id);
867 	return id;
868 }
869 
870 
871 status_t
872 close_port(port_id id)
873 {
874 	TRACE(("close_port(id = %ld)\n", id));
875 
876 	if (!sPortsActive || id < 0)
877 		return B_BAD_PORT_ID;
878 
879 	// get the port
880 	Port* port = get_locked_port(id);
881 	if (port == NULL) {
882 		TRACE(("close_port: invalid port_id %ld\n", id));
883 		return B_BAD_PORT_ID;
884 	}
885 	MutexLocker lock(&port->lock, true);
886 
887 	// mark port to disable writing - deleting the semaphores will
888 	// wake up waiting read/writes
889 	port->capacity = 0;
890 
891 	notify_port_select_events(port, B_EVENT_INVALID);
892 	port->select_infos = NULL;
893 
894 	port->read_condition.NotifyAll(false, B_BAD_PORT_ID);
895 	port->write_condition.NotifyAll(false, B_BAD_PORT_ID);
896 
897 	return B_OK;
898 }
899 
900 
901 status_t
902 delete_port(port_id id)
903 {
904 	TRACE(("delete_port(id = %ld)\n", id));
905 
906 	if (!sPortsActive || id < 0)
907 		return B_BAD_PORT_ID;
908 
909 	// get the port and remove it from the hash table and the team
910 	Port* port;
911 	MutexLocker locker;
912 	{
913 		MutexLocker portsLocker(sPortsLock);
914 
915 		port = sPorts.Lookup(id);
916 		if (port == NULL) {
917 			TRACE(("delete_port: invalid port_id %ld\n", id));
918 			return B_BAD_PORT_ID;
919 		}
920 
921 		sPorts.Remove(port);
922 		list_remove_link(&port->team_link);
923 
924 		sUsedPorts--;
925 
926 		locker.SetTo(port->lock, false);
927 
928 		uninit_port_locked(port);
929 	}
930 
931 	T(Delete(port));
932 
933 	locker.Unlock();
934 
935 	delete port;
936 
937 	return B_OK;
938 }
939 
940 
941 status_t
942 select_port(int32 id, struct select_info* info, bool kernel)
943 {
944 	if (id < 0)
945 		return B_BAD_PORT_ID;
946 
947 	// get the port
948 	Port* port = get_locked_port(id);
949 	if (port == NULL)
950 		return B_BAD_PORT_ID;
951 	MutexLocker locker(port->lock, true);
952 
953 	// port must not yet be closed
954 	if (is_port_closed(port))
955 		return B_BAD_PORT_ID;
956 
957 	if (!kernel && port->owner == team_get_kernel_team_id()) {
958 		// kernel port, but call from userland
959 		return B_NOT_ALLOWED;
960 	}
961 
962 	info->selected_events &= B_EVENT_READ | B_EVENT_WRITE | B_EVENT_INVALID;
963 
964 	if (info->selected_events != 0) {
965 		uint16 events = 0;
966 
967 		info->next = port->select_infos;
968 		port->select_infos = info;
969 
970 		// check for events
971 		if ((info->selected_events & B_EVENT_READ) != 0
972 			&& !port->messages.IsEmpty()) {
973 			events |= B_EVENT_READ;
974 		}
975 
976 		if (port->write_count > 0)
977 			events |= B_EVENT_WRITE;
978 
979 		if (events != 0)
980 			notify_select_events(info, events);
981 	}
982 
983 	return B_OK;
984 }
985 
986 
987 status_t
988 deselect_port(int32 id, struct select_info* info, bool kernel)
989 {
990 	if (id < 0)
991 		return B_BAD_PORT_ID;
992 	if (info->selected_events == 0)
993 		return B_OK;
994 
995 	// get the port
996 	Port* port = get_locked_port(id);
997 	if (port == NULL)
998 		return B_BAD_PORT_ID;
999 	MutexLocker locker(port->lock, true);
1000 
1001 	// find and remove the infos
1002 	select_info** infoLocation = &port->select_infos;
1003 	while (*infoLocation != NULL && *infoLocation != info)
1004 		infoLocation = &(*infoLocation)->next;
1005 
1006 	if (*infoLocation == info)
1007 		*infoLocation = info->next;
1008 
1009 	return B_OK;
1010 }
1011 
1012 
1013 port_id
1014 find_port(const char* name)
1015 {
1016 	TRACE(("find_port(name = \"%s\")\n", name));
1017 
1018 	if (!sPortsActive) {
1019 		panic("ports used too early!\n");
1020 		return B_NAME_NOT_FOUND;
1021 	}
1022 	if (name == NULL)
1023 		return B_BAD_VALUE;
1024 
1025 	MutexLocker portsLocker(sPortsLock);
1026 
1027 	for (PortHashTable::Iterator it = sPorts.GetIterator();
1028 		Port* port = it.Next();) {
1029 		if (!strcmp(name, port->lock.name))
1030 			return port->id;
1031 	}
1032 
1033 	return B_NAME_NOT_FOUND;
1034 }
1035 
1036 
1037 status_t
1038 _get_port_info(port_id id, port_info* info, size_t size)
1039 {
1040 	TRACE(("get_port_info(id = %ld)\n", id));
1041 
1042 	if (info == NULL || size != sizeof(port_info))
1043 		return B_BAD_VALUE;
1044 	if (!sPortsActive || id < 0)
1045 		return B_BAD_PORT_ID;
1046 
1047 	// get the port
1048 	Port* port = get_locked_port(id);
1049 	if (port == NULL) {
1050 		TRACE(("get_port_info: invalid port_id %ld\n", id));
1051 		return B_BAD_PORT_ID;
1052 	}
1053 	MutexLocker locker(port->lock, true);
1054 
1055 	// fill a port_info struct with info
1056 	fill_port_info(port, info, size);
1057 	return B_OK;
1058 }
1059 
1060 
1061 status_t
1062 _get_next_port_info(team_id teamID, int32* _cookie, struct port_info* info,
1063 	size_t size)
1064 {
1065 	TRACE(("get_next_port_info(team = %ld)\n", teamID));
1066 
1067 	if (info == NULL || size != sizeof(port_info) || _cookie == NULL
1068 		|| teamID < 0) {
1069 		return B_BAD_VALUE;
1070 	}
1071 	if (!sPortsActive)
1072 		return B_BAD_PORT_ID;
1073 
1074 	Team* team = Team::Get(teamID);
1075 	if (team == NULL)
1076 		return B_BAD_TEAM_ID;
1077 	BReference<Team> teamReference(team, true);
1078 
1079 	// iterate through the team's port list
1080 	MutexLocker portsLocker(sPortsLock);
1081 
1082 	int32 stopIndex = *_cookie;
1083 	int32 index = 0;
1084 
1085 	Port* port = (Port*)list_get_first_item(&team->port_list);
1086 	while (port != NULL) {
1087 		if (!is_port_closed(port)) {
1088 			if (index == stopIndex)
1089 				break;
1090 			index++;
1091 		}
1092 
1093 		port = (Port*)list_get_next_item(&team->port_list, port);
1094 	}
1095 
1096 	if (port == NULL)
1097 		return B_BAD_PORT_ID;
1098 
1099 	// fill in the port info
1100 	MutexLocker locker(port->lock);
1101 	portsLocker.Unlock();
1102 	fill_port_info(port, info, size);
1103 
1104 	*_cookie = stopIndex + 1;
1105 	return B_OK;
1106 }
1107 
1108 
1109 ssize_t
1110 port_buffer_size(port_id id)
1111 {
1112 	return port_buffer_size_etc(id, 0, 0);
1113 }
1114 
1115 
1116 ssize_t
1117 port_buffer_size_etc(port_id id, uint32 flags, bigtime_t timeout)
1118 {
1119 	port_message_info info;
1120 	status_t error = get_port_message_info_etc(id, &info, flags, timeout);
1121 	return error != B_OK ? error : info.size;
1122 }
1123 
1124 
1125 status_t
1126 _get_port_message_info_etc(port_id id, port_message_info* info,
1127 	size_t infoSize, uint32 flags, bigtime_t timeout)
1128 {
1129 	if (info == NULL || infoSize != sizeof(port_message_info))
1130 		return B_BAD_VALUE;
1131 	if (!sPortsActive || id < 0)
1132 		return B_BAD_PORT_ID;
1133 
1134 	flags &= B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT | B_RELATIVE_TIMEOUT
1135 		| B_ABSOLUTE_TIMEOUT;
1136 
1137 	// get the port
1138 	Port* port = get_locked_port(id);
1139 	if (port == NULL)
1140 		return B_BAD_PORT_ID;
1141 	MutexLocker locker(port->lock, true);
1142 
1143 	if (is_port_closed(port) && port->messages.IsEmpty()) {
1144 		T(Info(port, 0, B_BAD_PORT_ID));
1145 		TRACE(("_get_port_message_info_etc(): closed port %ld\n", id));
1146 		return B_BAD_PORT_ID;
1147 	}
1148 
1149 	while (port->read_count == 0) {
1150 		// We need to wait for a message to appear
1151 		if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0)
1152 			return B_WOULD_BLOCK;
1153 
1154 		ConditionVariableEntry entry;
1155 		port->read_condition.Add(&entry);
1156 
1157 		locker.Unlock();
1158 
1159 		// block if no message, or, if B_TIMEOUT flag set, block with timeout
1160 		status_t status = entry.Wait(flags, timeout);
1161 
1162 		if (status != B_OK) {
1163 			T(Info(port, 0, status));
1164 			return status;
1165 		}
1166 
1167 		// re-lock
1168 		Port* newPort = get_locked_port(id);
1169 		if (newPort == NULL) {
1170 			T(Info(id, 0, 0, 0, B_BAD_PORT_ID));
1171 			return B_BAD_PORT_ID;
1172 		}
1173 		locker.SetTo(newPort->lock, true);
1174 
1175 		if (newPort != port
1176 			|| (is_port_closed(port) && port->messages.IsEmpty())) {
1177 			// the port is no longer there
1178 			T(Info(id, 0, 0, 0, B_BAD_PORT_ID));
1179 			return B_BAD_PORT_ID;
1180 		}
1181 	}
1182 
1183 	// determine tail & get the length of the message
1184 	port_message* message = port->messages.Head();
1185 	if (message == NULL) {
1186 		panic("port %" B_PRId32 ": no messages found\n", port->id);
1187 		return B_ERROR;
1188 	}
1189 
1190 	info->size = message->size;
1191 	info->sender = message->sender;
1192 	info->sender_group = message->sender_group;
1193 	info->sender_team = message->sender_team;
1194 
1195 	T(Info(id, id->read_count, id->write_count, message->code, B_OK));
1196 
1197 	// notify next one, as we haven't read from the port
1198 	port->read_condition.NotifyOne();
1199 
1200 	return B_OK;
1201 }
1202 
1203 
1204 ssize_t
1205 port_count(port_id id)
1206 {
1207 	if (!sPortsActive || id < 0)
1208 		return B_BAD_PORT_ID;
1209 
1210 	// get the port
1211 	Port* port = get_locked_port(id);
1212 	if (port == NULL) {
1213 		TRACE(("port_count: invalid port_id %ld\n", id));
1214 		return B_BAD_PORT_ID;
1215 	}
1216 	MutexLocker locker(port->lock, true);
1217 
1218 	// return count of messages
1219 	return port->read_count;
1220 }
1221 
1222 
1223 ssize_t
1224 read_port(port_id port, int32* msgCode, void* buffer, size_t bufferSize)
1225 {
1226 	return read_port_etc(port, msgCode, buffer, bufferSize, 0, 0);
1227 }
1228 
1229 
1230 ssize_t
1231 read_port_etc(port_id id, int32* _code, void* buffer, size_t bufferSize,
1232 	uint32 flags, bigtime_t timeout)
1233 {
1234 	if (!sPortsActive || id < 0)
1235 		return B_BAD_PORT_ID;
1236 	if ((buffer == NULL && bufferSize > 0) || timeout < 0)
1237 		return B_BAD_VALUE;
1238 
1239 	bool userCopy = (flags & PORT_FLAG_USE_USER_MEMCPY) != 0;
1240 	bool peekOnly = !userCopy && (flags & B_PEEK_PORT_MESSAGE) != 0;
1241 		// TODO: we could allow peeking for user apps now
1242 
1243 	flags &= B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT | B_RELATIVE_TIMEOUT
1244 		| B_ABSOLUTE_TIMEOUT;
1245 
1246 	// get the port
1247 	Port* port = get_locked_port(id);
1248 	if (port == NULL)
1249 		return B_BAD_PORT_ID;
1250 	MutexLocker locker(port->lock, true);
1251 
1252 	if (is_port_closed(port) && port->messages.IsEmpty()) {
1253 		T(Read(port, 0, B_BAD_PORT_ID));
1254 		TRACE(("read_port_etc(): closed port %ld\n", id));
1255 		return B_BAD_PORT_ID;
1256 	}
1257 
1258 	while (port->read_count == 0) {
1259 		if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0)
1260 			return B_WOULD_BLOCK;
1261 
1262 		// We need to wait for a message to appear
1263 		ConditionVariableEntry entry;
1264 		port->read_condition.Add(&entry);
1265 
1266 		locker.Unlock();
1267 
1268 		// block if no message, or, if B_TIMEOUT flag set, block with timeout
1269 		status_t status = entry.Wait(flags, timeout);
1270 
1271 		// re-lock
1272 		Port* newPort = get_locked_port(id);
1273 		if (newPort == NULL) {
1274 			T(Read(id, 0, 0, 0, B_BAD_PORT_ID));
1275 			return B_BAD_PORT_ID;
1276 		}
1277 		locker.SetTo(newPort->lock, true);
1278 
1279 		if (newPort != port
1280 			|| (is_port_closed(port) && port->messages.IsEmpty())) {
1281 			// the port is no longer there
1282 			T(Read(id, 0, 0, 0, B_BAD_PORT_ID));
1283 			return B_BAD_PORT_ID;
1284 		}
1285 
1286 		if (status != B_OK) {
1287 			T(Read(port, 0, status));
1288 			return status;
1289 		}
1290 	}
1291 
1292 	// determine tail & get the length of the message
1293 	port_message* message = port->messages.Head();
1294 	if (message == NULL) {
1295 		panic("port %" B_PRId32 ": no messages found\n", port->id);
1296 		return B_ERROR;
1297 	}
1298 
1299 	if (peekOnly) {
1300 		size_t size = copy_port_message(message, _code, buffer, bufferSize,
1301 			userCopy);
1302 
1303 		T(Read(port, message->code, size));
1304 
1305 		port->read_condition.NotifyOne();
1306 			// we only peeked, but didn't grab the message
1307 		return size;
1308 	}
1309 
1310 	port->messages.RemoveHead();
1311 	port->total_count++;
1312 	port->write_count++;
1313 	port->read_count--;
1314 
1315 	notify_port_select_events(port, B_EVENT_WRITE);
1316 	port->write_condition.NotifyOne();
1317 		// make one spot in queue available again for write
1318 
1319 	T(Read(id, port->read_count, port->write_count, message->code,
1320 		min_c(bufferSize, message->size)));
1321 
1322 	locker.Unlock();
1323 
1324 	size_t size = copy_port_message(message, _code, buffer, bufferSize,
1325 		userCopy);
1326 
1327 	put_port_message(message);
1328 	return size;
1329 }
1330 
1331 
1332 status_t
1333 write_port(port_id id, int32 msgCode, const void* buffer, size_t bufferSize)
1334 {
1335 	iovec vec = { (void*)buffer, bufferSize };
1336 
1337 	return writev_port_etc(id, msgCode, &vec, 1, bufferSize, 0, 0);
1338 }
1339 
1340 
1341 status_t
1342 write_port_etc(port_id id, int32 msgCode, const void* buffer,
1343 	size_t bufferSize, uint32 flags, bigtime_t timeout)
1344 {
1345 	iovec vec = { (void*)buffer, bufferSize };
1346 
1347 	return writev_port_etc(id, msgCode, &vec, 1, bufferSize, flags, timeout);
1348 }
1349 
1350 
1351 status_t
1352 writev_port_etc(port_id id, int32 msgCode, const iovec* msgVecs,
1353 	size_t vecCount, size_t bufferSize, uint32 flags, bigtime_t timeout)
1354 {
1355 	if (!sPortsActive || id < 0)
1356 		return B_BAD_PORT_ID;
1357 	if (bufferSize > PORT_MAX_MESSAGE_SIZE)
1358 		return B_BAD_VALUE;
1359 
1360 	// mask irrelevant flags (for acquire_sem() usage)
1361 	flags &= B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT | B_RELATIVE_TIMEOUT
1362 		| B_ABSOLUTE_TIMEOUT;
1363 	if ((flags & B_RELATIVE_TIMEOUT) != 0
1364 		&& timeout != B_INFINITE_TIMEOUT && timeout > 0) {
1365 		// Make the timeout absolute, since we have more than one step where
1366 		// we might have to wait
1367 		flags = (flags & ~B_RELATIVE_TIMEOUT) | B_ABSOLUTE_TIMEOUT;
1368 		timeout += system_time();
1369 	}
1370 
1371 	bool userCopy = (flags & PORT_FLAG_USE_USER_MEMCPY) > 0;
1372 
1373 	status_t status;
1374 	port_message* message = NULL;
1375 
1376 	// get the port
1377 	Port* port = get_locked_port(id);
1378 	if (port == NULL) {
1379 		TRACE(("write_port_etc: invalid port_id %ld\n", id));
1380 		return B_BAD_PORT_ID;
1381 	}
1382 	MutexLocker locker(port->lock, true);
1383 
1384 	if (is_port_closed(port)) {
1385 		TRACE(("write_port_etc: port %ld closed\n", id));
1386 		return B_BAD_PORT_ID;
1387 	}
1388 
1389 	if (port->write_count <= 0) {
1390 		if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0)
1391 			return B_WOULD_BLOCK;
1392 
1393 		port->write_count--;
1394 
1395 		// We need to block in order to wait for a free message slot
1396 		ConditionVariableEntry entry;
1397 		port->write_condition.Add(&entry);
1398 
1399 		locker.Unlock();
1400 
1401 		status = entry.Wait(flags, timeout);
1402 
1403 		// re-lock
1404 		Port* newPort = get_locked_port(id);
1405 		if (newPort == NULL) {
1406 			T(Write(id, 0, 0, 0, 0, B_BAD_PORT_ID));
1407 			return B_BAD_PORT_ID;
1408 		}
1409 		locker.SetTo(newPort->lock, true);
1410 
1411 		if (newPort != port || is_port_closed(port)) {
1412 			// the port is no longer there
1413 			T(Write(id, 0, 0, 0, 0, B_BAD_PORT_ID));
1414 			return B_BAD_PORT_ID;
1415 		}
1416 
1417 		if (status != B_OK)
1418 			goto error;
1419 	} else
1420 		port->write_count--;
1421 
1422 	status = get_port_message(msgCode, bufferSize, flags, timeout,
1423 		&message, *port);
1424 	if (status != B_OK) {
1425 		if (status == B_BAD_PORT_ID) {
1426 			// the port had to be unlocked and is now no longer there
1427 			T(Write(id, 0, 0, 0, 0, B_BAD_PORT_ID));
1428 			return B_BAD_PORT_ID;
1429 		}
1430 
1431 		goto error;
1432 	}
1433 
1434 	// sender credentials
1435 	message->sender = geteuid();
1436 	message->sender_group = getegid();
1437 	message->sender_team = team_get_current_team_id();
1438 
1439 	if (bufferSize > 0) {
1440 		size_t offset = 0;
1441 		for (uint32 i = 0; i < vecCount; i++) {
1442 			size_t bytes = msgVecs[i].iov_len;
1443 			if (bytes > bufferSize)
1444 				bytes = bufferSize;
1445 
1446 			if (userCopy) {
1447 				status_t status = user_memcpy(message->buffer + offset,
1448 					msgVecs[i].iov_base, bytes);
1449 				if (status != B_OK) {
1450 					put_port_message(message);
1451 					goto error;
1452 				}
1453 			} else
1454 				memcpy(message->buffer + offset, msgVecs[i].iov_base, bytes);
1455 
1456 			bufferSize -= bytes;
1457 			if (bufferSize == 0)
1458 				break;
1459 
1460 			offset += bytes;
1461 		}
1462 	}
1463 
1464 	port->messages.Add(message);
1465 	port->read_count++;
1466 
1467 	T(Write(id, port->read_count, port->write_count, message->code,
1468 		message->size, B_OK));
1469 
1470 	notify_port_select_events(port, B_EVENT_READ);
1471 	port->read_condition.NotifyOne();
1472 	return B_OK;
1473 
1474 error:
1475 	// Give up our slot in the queue again, and let someone else
1476 	// try and fail
1477 	T(Write(id, port->read_count, port->write_count, 0, 0, status));
1478 	port->write_count++;
1479 	notify_port_select_events(port, B_EVENT_WRITE);
1480 	port->write_condition.NotifyOne();
1481 
1482 	return status;
1483 }
1484 
1485 
1486 status_t
1487 set_port_owner(port_id id, team_id newTeamID)
1488 {
1489 	TRACE(("set_port_owner(id = %ld, team = %ld)\n", id, newTeamID));
1490 
1491 	if (id < 0)
1492 		return B_BAD_PORT_ID;
1493 
1494 	// get the new team
1495 	Team* team = Team::Get(newTeamID);
1496 	if (team == NULL)
1497 		return B_BAD_TEAM_ID;
1498 	BReference<Team> teamReference(team, true);
1499 
1500 	// get the port
1501 	MutexLocker portsLocker(sPortsLock);
1502 	Port* port = sPorts.Lookup(id);
1503 	if (port == NULL) {
1504 		TRACE(("set_port_owner: invalid port_id %ld\n", id));
1505 		return B_BAD_PORT_ID;
1506 	}
1507 	MutexLocker locker(port->lock);
1508 
1509 	// transfer ownership to other team
1510 	if (team->id != port->owner) {
1511 		list_remove_link(&port->team_link);
1512 		list_add_item(&team->port_list, &port->team_link);
1513 		port->owner = team->id;
1514 	}
1515 
1516 	T(OwnerChange(port, team->id, B_OK));
1517 	return B_OK;
1518 }
1519 
1520 
1521 //	#pragma mark - syscalls
1522 
1523 
1524 port_id
1525 _user_create_port(int32 queueLength, const char *userName)
1526 {
1527 	char name[B_OS_NAME_LENGTH];
1528 
1529 	if (userName == NULL)
1530 		return create_port(queueLength, NULL);
1531 
1532 	if (!IS_USER_ADDRESS(userName)
1533 		|| user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK)
1534 		return B_BAD_ADDRESS;
1535 
1536 	return create_port(queueLength, name);
1537 }
1538 
1539 
1540 status_t
1541 _user_close_port(port_id id)
1542 {
1543 	return close_port(id);
1544 }
1545 
1546 
1547 status_t
1548 _user_delete_port(port_id id)
1549 {
1550 	return delete_port(id);
1551 }
1552 
1553 
1554 port_id
1555 _user_find_port(const char *userName)
1556 {
1557 	char name[B_OS_NAME_LENGTH];
1558 
1559 	if (userName == NULL)
1560 		return B_BAD_VALUE;
1561 	if (!IS_USER_ADDRESS(userName)
1562 		|| user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK)
1563 		return B_BAD_ADDRESS;
1564 
1565 	return find_port(name);
1566 }
1567 
1568 
1569 status_t
1570 _user_get_port_info(port_id id, struct port_info *userInfo)
1571 {
1572 	struct port_info info;
1573 	status_t status;
1574 
1575 	if (userInfo == NULL)
1576 		return B_BAD_VALUE;
1577 	if (!IS_USER_ADDRESS(userInfo))
1578 		return B_BAD_ADDRESS;
1579 
1580 	status = get_port_info(id, &info);
1581 
1582 	// copy back to user space
1583 	if (status == B_OK
1584 		&& user_memcpy(userInfo, &info, sizeof(struct port_info)) < B_OK)
1585 		return B_BAD_ADDRESS;
1586 
1587 	return status;
1588 }
1589 
1590 
1591 status_t
1592 _user_get_next_port_info(team_id team, int32 *userCookie,
1593 	struct port_info *userInfo)
1594 {
1595 	struct port_info info;
1596 	status_t status;
1597 	int32 cookie;
1598 
1599 	if (userCookie == NULL || userInfo == NULL)
1600 		return B_BAD_VALUE;
1601 	if (!IS_USER_ADDRESS(userCookie) || !IS_USER_ADDRESS(userInfo)
1602 		|| user_memcpy(&cookie, userCookie, sizeof(int32)) < B_OK)
1603 		return B_BAD_ADDRESS;
1604 
1605 	status = get_next_port_info(team, &cookie, &info);
1606 
1607 	// copy back to user space
1608 	if (user_memcpy(userCookie, &cookie, sizeof(int32)) < B_OK
1609 		|| (status == B_OK && user_memcpy(userInfo, &info,
1610 				sizeof(struct port_info)) < B_OK))
1611 		return B_BAD_ADDRESS;
1612 
1613 	return status;
1614 }
1615 
1616 
1617 ssize_t
1618 _user_port_buffer_size_etc(port_id port, uint32 flags, bigtime_t timeout)
1619 {
1620 	syscall_restart_handle_timeout_pre(flags, timeout);
1621 
1622 	status_t status = port_buffer_size_etc(port, flags | B_CAN_INTERRUPT,
1623 		timeout);
1624 
1625 	return syscall_restart_handle_timeout_post(status, timeout);
1626 }
1627 
1628 
1629 ssize_t
1630 _user_port_count(port_id port)
1631 {
1632 	return port_count(port);
1633 }
1634 
1635 
1636 status_t
1637 _user_set_port_owner(port_id port, team_id team)
1638 {
1639 	return set_port_owner(port, team);
1640 }
1641 
1642 
1643 ssize_t
1644 _user_read_port_etc(port_id port, int32 *userCode, void *userBuffer,
1645 	size_t bufferSize, uint32 flags, bigtime_t timeout)
1646 {
1647 	int32 messageCode;
1648 	ssize_t	bytesRead;
1649 
1650 	syscall_restart_handle_timeout_pre(flags, timeout);
1651 
1652 	if (userBuffer == NULL && bufferSize != 0)
1653 		return B_BAD_VALUE;
1654 	if ((userCode != NULL && !IS_USER_ADDRESS(userCode))
1655 		|| (userBuffer != NULL && !IS_USER_ADDRESS(userBuffer)))
1656 		return B_BAD_ADDRESS;
1657 
1658 	bytesRead = read_port_etc(port, &messageCode, userBuffer, bufferSize,
1659 		flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT, timeout);
1660 
1661 	if (bytesRead >= 0 && userCode != NULL
1662 		&& user_memcpy(userCode, &messageCode, sizeof(int32)) < B_OK)
1663 		return B_BAD_ADDRESS;
1664 
1665 	return syscall_restart_handle_timeout_post(bytesRead, timeout);
1666 }
1667 
1668 
1669 status_t
1670 _user_write_port_etc(port_id port, int32 messageCode, const void *userBuffer,
1671 	size_t bufferSize, uint32 flags, bigtime_t timeout)
1672 {
1673 	iovec vec = { (void *)userBuffer, bufferSize };
1674 
1675 	syscall_restart_handle_timeout_pre(flags, timeout);
1676 
1677 	if (userBuffer == NULL && bufferSize != 0)
1678 		return B_BAD_VALUE;
1679 	if (userBuffer != NULL && !IS_USER_ADDRESS(userBuffer))
1680 		return B_BAD_ADDRESS;
1681 
1682 	status_t status = writev_port_etc(port, messageCode, &vec, 1, bufferSize,
1683 		flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT, timeout);
1684 
1685 	return syscall_restart_handle_timeout_post(status, timeout);
1686 }
1687 
1688 
1689 status_t
1690 _user_writev_port_etc(port_id port, int32 messageCode, const iovec *userVecs,
1691 	size_t vecCount, size_t bufferSize, uint32 flags, bigtime_t timeout)
1692 {
1693 	syscall_restart_handle_timeout_pre(flags, timeout);
1694 
1695 	if (userVecs == NULL && bufferSize != 0)
1696 		return B_BAD_VALUE;
1697 	if (userVecs != NULL && !IS_USER_ADDRESS(userVecs))
1698 		return B_BAD_ADDRESS;
1699 
1700 	iovec *vecs = NULL;
1701 	if (userVecs && vecCount != 0) {
1702 		vecs = (iovec*)malloc(sizeof(iovec) * vecCount);
1703 		if (vecs == NULL)
1704 			return B_NO_MEMORY;
1705 
1706 		if (user_memcpy(vecs, userVecs, sizeof(iovec) * vecCount) < B_OK) {
1707 			free(vecs);
1708 			return B_BAD_ADDRESS;
1709 		}
1710 	}
1711 
1712 	status_t status = writev_port_etc(port, messageCode, vecs, vecCount,
1713 		bufferSize, flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT,
1714 		timeout);
1715 
1716 	free(vecs);
1717 	return syscall_restart_handle_timeout_post(status, timeout);
1718 }
1719 
1720 
1721 status_t
1722 _user_get_port_message_info_etc(port_id port, port_message_info *userInfo,
1723 	size_t infoSize, uint32 flags, bigtime_t timeout)
1724 {
1725 	if (userInfo == NULL || infoSize != sizeof(port_message_info))
1726 		return B_BAD_VALUE;
1727 
1728 	syscall_restart_handle_timeout_pre(flags, timeout);
1729 
1730 	port_message_info info;
1731 	status_t error = _get_port_message_info_etc(port, &info, sizeof(info),
1732 		flags | B_CAN_INTERRUPT, timeout);
1733 
1734 	// copy info to userland
1735 	if (error == B_OK && (!IS_USER_ADDRESS(userInfo)
1736 			|| user_memcpy(userInfo, &info, sizeof(info)) != B_OK)) {
1737 		error = B_BAD_ADDRESS;
1738 	}
1739 
1740 	return syscall_restart_handle_timeout_post(error, timeout);
1741 }
1742