xref: /haiku/src/system/kernel/port.cpp (revision 820dca4df6c7bf955c46e8f6521b9408f50b2900)
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 	sPortsActive = true;
796 	return B_OK;
797 }
798 
799 
800 //	#pragma mark - public kernel API
801 
802 
803 port_id
804 create_port(int32 queueLength, const char* name)
805 {
806 	TRACE(("create_port(queueLength = %ld, name = \"%s\")\n", queueLength,
807 		name));
808 
809 	if (!sPortsActive) {
810 		panic("ports used too early!\n");
811 		return B_BAD_PORT_ID;
812 	}
813 	if (queueLength < 1 || queueLength > MAX_QUEUE_LENGTH)
814 		return B_BAD_VALUE;
815 
816 	Team* team = thread_get_current_thread()->team;
817 	if (team == NULL)
818 		return B_BAD_TEAM_ID;
819 
820 	// check & dup name
821 	char* nameBuffer = strdup(name != NULL ? name : "unnamed port");
822 	if (nameBuffer == NULL)
823 		return B_NO_MEMORY;
824 
825 	// create a port
826 	Port* port = new(std::nothrow) Port(team_get_current_team_id(), queueLength,
827 		nameBuffer);
828 	if (port == NULL) {
829 		free(nameBuffer);
830 		return B_NO_MEMORY;
831 	}
832 	ObjectDeleter<Port> portDeleter(port);
833 
834 	MutexLocker locker(sPortsLock);
835 
836 	// check the ports limit
837 	if (sUsedPorts >= sMaxPorts)
838 		return B_NO_MORE_PORTS;
839 
840 	sUsedPorts++;
841 
842 	// allocate a port ID
843 	do {
844 		port->id = sNextPortID++;
845 
846 		// handle integer overflow
847 		if (sNextPortID < 0)
848 			sNextPortID = 1;
849 	} while (sPorts.Lookup(port->id) != NULL);
850 
851 	// insert port in table and team list
852 	sPorts.Insert(port);
853 	list_add_item(&team->port_list, &port->team_link);
854 	portDeleter.Detach();
855 
856 	// tracing, notifications, etc.
857 	T(Create(port));
858 
859 	port_id id = port->id;
860 
861 	locker.Unlock();
862 
863 	TRACE(("create_port() done: port created %ld\n", id));
864 
865 	sNotificationService.Notify(PORT_ADDED, id);
866 	return id;
867 }
868 
869 
870 status_t
871 close_port(port_id id)
872 {
873 	TRACE(("close_port(id = %ld)\n", id));
874 
875 	if (!sPortsActive || id < 0)
876 		return B_BAD_PORT_ID;
877 
878 	// get the port
879 	Port* port = get_locked_port(id);
880 	if (port == NULL) {
881 		TRACE(("close_port: invalid port_id %ld\n", id));
882 		return B_BAD_PORT_ID;
883 	}
884 	MutexLocker lock(&port->lock, true);
885 
886 	// mark port to disable writing - deleting the semaphores will
887 	// wake up waiting read/writes
888 	port->capacity = 0;
889 
890 	notify_port_select_events(port, B_EVENT_INVALID);
891 	port->select_infos = NULL;
892 
893 	port->read_condition.NotifyAll(false, B_BAD_PORT_ID);
894 	port->write_condition.NotifyAll(false, B_BAD_PORT_ID);
895 
896 	return B_OK;
897 }
898 
899 
900 status_t
901 delete_port(port_id id)
902 {
903 	TRACE(("delete_port(id = %ld)\n", id));
904 
905 	if (!sPortsActive || id < 0)
906 		return B_BAD_PORT_ID;
907 
908 	// get the port and remove it from the hash table and the team
909 	Port* port;
910 	MutexLocker locker;
911 	{
912 		MutexLocker portsLocker(sPortsLock);
913 
914 		port = sPorts.Lookup(id);
915 		if (port == NULL) {
916 			TRACE(("delete_port: invalid port_id %ld\n", id));
917 			return B_BAD_PORT_ID;
918 		}
919 
920 		sPorts.Remove(port);
921 		list_remove_link(&port->team_link);
922 
923 		sUsedPorts--;
924 
925 		locker.SetTo(port->lock, false);
926 
927 		uninit_port_locked(port);
928 	}
929 
930 	T(Delete(port));
931 
932 	locker.Unlock();
933 
934 	delete port;
935 
936 	return B_OK;
937 }
938 
939 
940 status_t
941 select_port(int32 id, struct select_info* info, bool kernel)
942 {
943 	if (id < 0)
944 		return B_BAD_PORT_ID;
945 
946 	// get the port
947 	Port* port = get_locked_port(id);
948 	if (port == NULL)
949 		return B_BAD_PORT_ID;
950 	MutexLocker locker(port->lock, true);
951 
952 	// port must not yet be closed
953 	if (is_port_closed(port))
954 		return B_BAD_PORT_ID;
955 
956 	if (!kernel && port->owner == team_get_kernel_team_id()) {
957 		// kernel port, but call from userland
958 		return B_NOT_ALLOWED;
959 	}
960 
961 	info->selected_events &= B_EVENT_READ | B_EVENT_WRITE | B_EVENT_INVALID;
962 
963 	if (info->selected_events != 0) {
964 		uint16 events = 0;
965 
966 		info->next = port->select_infos;
967 		port->select_infos = info;
968 
969 		// check for events
970 		if ((info->selected_events & B_EVENT_READ) != 0
971 			&& !port->messages.IsEmpty()) {
972 			events |= B_EVENT_READ;
973 		}
974 
975 		if (port->write_count > 0)
976 			events |= B_EVENT_WRITE;
977 
978 		if (events != 0)
979 			notify_select_events(info, events);
980 	}
981 
982 	return B_OK;
983 }
984 
985 
986 status_t
987 deselect_port(int32 id, struct select_info* info, bool kernel)
988 {
989 	if (id < 0)
990 		return B_BAD_PORT_ID;
991 	if (info->selected_events == 0)
992 		return B_OK;
993 
994 	// get the port
995 	Port* port = get_locked_port(id);
996 	if (port == NULL)
997 		return B_BAD_PORT_ID;
998 	MutexLocker locker(port->lock, true);
999 
1000 	// find and remove the infos
1001 	select_info** infoLocation = &port->select_infos;
1002 	while (*infoLocation != NULL && *infoLocation != info)
1003 		infoLocation = &(*infoLocation)->next;
1004 
1005 	if (*infoLocation == info)
1006 		*infoLocation = info->next;
1007 
1008 	return B_OK;
1009 }
1010 
1011 
1012 port_id
1013 find_port(const char* name)
1014 {
1015 	TRACE(("find_port(name = \"%s\")\n", name));
1016 
1017 	if (!sPortsActive) {
1018 		panic("ports used too early!\n");
1019 		return B_NAME_NOT_FOUND;
1020 	}
1021 	if (name == NULL)
1022 		return B_BAD_VALUE;
1023 
1024 	MutexLocker portsLocker(sPortsLock);
1025 
1026 	for (PortHashTable::Iterator it = sPorts.GetIterator();
1027 		Port* port = it.Next();) {
1028 		if (!strcmp(name, port->lock.name))
1029 			return port->id;
1030 	}
1031 
1032 	return B_NAME_NOT_FOUND;
1033 }
1034 
1035 
1036 status_t
1037 _get_port_info(port_id id, port_info* info, size_t size)
1038 {
1039 	TRACE(("get_port_info(id = %ld)\n", id));
1040 
1041 	if (info == NULL || size != sizeof(port_info))
1042 		return B_BAD_VALUE;
1043 	if (!sPortsActive || id < 0)
1044 		return B_BAD_PORT_ID;
1045 
1046 	// get the port
1047 	Port* port = get_locked_port(id);
1048 	if (port == NULL) {
1049 		TRACE(("get_port_info: invalid port_id %ld\n", id));
1050 		return B_BAD_PORT_ID;
1051 	}
1052 	MutexLocker locker(port->lock, true);
1053 
1054 	// fill a port_info struct with info
1055 	fill_port_info(port, info, size);
1056 	return B_OK;
1057 }
1058 
1059 
1060 status_t
1061 _get_next_port_info(team_id teamID, int32* _cookie, struct port_info* info,
1062 	size_t size)
1063 {
1064 	TRACE(("get_next_port_info(team = %ld)\n", teamID));
1065 
1066 	if (info == NULL || size != sizeof(port_info) || _cookie == NULL
1067 		|| teamID < 0) {
1068 		return B_BAD_VALUE;
1069 	}
1070 	if (!sPortsActive)
1071 		return B_BAD_PORT_ID;
1072 
1073 	Team* team = Team::Get(teamID);
1074 	if (team == NULL)
1075 		return B_BAD_TEAM_ID;
1076 	BReference<Team> teamReference(team, true);
1077 
1078 	// iterate through the team's port list
1079 	MutexLocker portsLocker(sPortsLock);
1080 
1081 	int32 stopIndex = *_cookie;
1082 	int32 index = 0;
1083 
1084 	Port* port = (Port*)list_get_first_item(&team->port_list);
1085 	while (port != NULL) {
1086 		if (!is_port_closed(port)) {
1087 			if (index == stopIndex)
1088 				break;
1089 			index++;
1090 		}
1091 
1092 		port = (Port*)list_get_next_item(&team->port_list, port);
1093 	}
1094 
1095 	if (port == NULL)
1096 		return B_BAD_PORT_ID;
1097 
1098 	// fill in the port info
1099 	MutexLocker locker(port->lock);
1100 	portsLocker.Unlock();
1101 	fill_port_info(port, info, size);
1102 
1103 	*_cookie = stopIndex + 1;
1104 	return B_OK;
1105 }
1106 
1107 
1108 ssize_t
1109 port_buffer_size(port_id id)
1110 {
1111 	return port_buffer_size_etc(id, 0, 0);
1112 }
1113 
1114 
1115 ssize_t
1116 port_buffer_size_etc(port_id id, uint32 flags, bigtime_t timeout)
1117 {
1118 	port_message_info info;
1119 	status_t error = get_port_message_info_etc(id, &info, flags, timeout);
1120 	return error != B_OK ? error : info.size;
1121 }
1122 
1123 
1124 status_t
1125 _get_port_message_info_etc(port_id id, port_message_info* info,
1126 	size_t infoSize, uint32 flags, bigtime_t timeout)
1127 {
1128 	if (info == NULL || infoSize != sizeof(port_message_info))
1129 		return B_BAD_VALUE;
1130 	if (!sPortsActive || id < 0)
1131 		return B_BAD_PORT_ID;
1132 
1133 	flags &= B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT | B_RELATIVE_TIMEOUT
1134 		| B_ABSOLUTE_TIMEOUT;
1135 
1136 	// get the port
1137 	Port* port = get_locked_port(id);
1138 	if (port == NULL)
1139 		return B_BAD_PORT_ID;
1140 	MutexLocker locker(port->lock, true);
1141 
1142 	if (is_port_closed(port) && port->messages.IsEmpty()) {
1143 		T(Info(port, 0, B_BAD_PORT_ID));
1144 		TRACE(("_get_port_message_info_etc(): closed port %ld\n", id));
1145 		return B_BAD_PORT_ID;
1146 	}
1147 
1148 	while (port->read_count == 0) {
1149 		// We need to wait for a message to appear
1150 		if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0)
1151 			return B_WOULD_BLOCK;
1152 
1153 		ConditionVariableEntry entry;
1154 		port->read_condition.Add(&entry);
1155 
1156 		locker.Unlock();
1157 
1158 		// block if no message, or, if B_TIMEOUT flag set, block with timeout
1159 		status_t status = entry.Wait(flags, timeout);
1160 
1161 		if (status != B_OK) {
1162 			T(Info(port, 0, status));
1163 			return status;
1164 		}
1165 
1166 		// re-lock
1167 		Port* newPort = get_locked_port(id);
1168 		if (newPort == NULL) {
1169 			T(Info(id, 0, 0, 0, B_BAD_PORT_ID));
1170 			return B_BAD_PORT_ID;
1171 		}
1172 		locker.SetTo(newPort->lock, true);
1173 
1174 		if (newPort != port
1175 			|| (is_port_closed(port) && port->messages.IsEmpty())) {
1176 			// the port is no longer there
1177 			T(Info(id, 0, 0, 0, B_BAD_PORT_ID));
1178 			return B_BAD_PORT_ID;
1179 		}
1180 	}
1181 
1182 	// determine tail & get the length of the message
1183 	port_message* message = port->messages.Head();
1184 	if (message == NULL) {
1185 		panic("port %" B_PRId32 ": no messages found\n", port->id);
1186 		return B_ERROR;
1187 	}
1188 
1189 	info->size = message->size;
1190 	info->sender = message->sender;
1191 	info->sender_group = message->sender_group;
1192 	info->sender_team = message->sender_team;
1193 
1194 	T(Info(id, id->read_count, id->write_count, message->code, B_OK));
1195 
1196 	// notify next one, as we haven't read from the port
1197 	port->read_condition.NotifyOne();
1198 
1199 	return B_OK;
1200 }
1201 
1202 
1203 ssize_t
1204 port_count(port_id id)
1205 {
1206 	if (!sPortsActive || id < 0)
1207 		return B_BAD_PORT_ID;
1208 
1209 	// get the port
1210 	Port* port = get_locked_port(id);
1211 	if (port == NULL) {
1212 		TRACE(("port_count: invalid port_id %ld\n", id));
1213 		return B_BAD_PORT_ID;
1214 	}
1215 	MutexLocker locker(port->lock, true);
1216 
1217 	// return count of messages
1218 	return port->read_count;
1219 }
1220 
1221 
1222 ssize_t
1223 read_port(port_id port, int32* msgCode, void* buffer, size_t bufferSize)
1224 {
1225 	return read_port_etc(port, msgCode, buffer, bufferSize, 0, 0);
1226 }
1227 
1228 
1229 ssize_t
1230 read_port_etc(port_id id, int32* _code, void* buffer, size_t bufferSize,
1231 	uint32 flags, bigtime_t timeout)
1232 {
1233 	if (!sPortsActive || id < 0)
1234 		return B_BAD_PORT_ID;
1235 	if ((buffer == NULL && bufferSize > 0) || timeout < 0)
1236 		return B_BAD_VALUE;
1237 
1238 	bool userCopy = (flags & PORT_FLAG_USE_USER_MEMCPY) != 0;
1239 	bool peekOnly = !userCopy && (flags & B_PEEK_PORT_MESSAGE) != 0;
1240 		// TODO: we could allow peeking for user apps now
1241 
1242 	flags &= B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT | B_RELATIVE_TIMEOUT
1243 		| B_ABSOLUTE_TIMEOUT;
1244 
1245 	// get the port
1246 	Port* port = get_locked_port(id);
1247 	if (port == NULL)
1248 		return B_BAD_PORT_ID;
1249 	MutexLocker locker(port->lock, true);
1250 
1251 	if (is_port_closed(port) && port->messages.IsEmpty()) {
1252 		T(Read(port, 0, B_BAD_PORT_ID));
1253 		TRACE(("read_port_etc(): closed port %ld\n", id));
1254 		return B_BAD_PORT_ID;
1255 	}
1256 
1257 	while (port->read_count == 0) {
1258 		if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0)
1259 			return B_WOULD_BLOCK;
1260 
1261 		// We need to wait for a message to appear
1262 		ConditionVariableEntry entry;
1263 		port->read_condition.Add(&entry);
1264 
1265 		locker.Unlock();
1266 
1267 		// block if no message, or, if B_TIMEOUT flag set, block with timeout
1268 		status_t status = entry.Wait(flags, timeout);
1269 
1270 		// re-lock
1271 		Port* newPort = get_locked_port(id);
1272 		if (newPort == NULL) {
1273 			T(Read(id, 0, 0, 0, B_BAD_PORT_ID));
1274 			return B_BAD_PORT_ID;
1275 		}
1276 		locker.SetTo(newPort->lock, true);
1277 
1278 		if (newPort != port
1279 			|| (is_port_closed(port) && port->messages.IsEmpty())) {
1280 			// the port is no longer there
1281 			T(Read(id, 0, 0, 0, B_BAD_PORT_ID));
1282 			return B_BAD_PORT_ID;
1283 		}
1284 
1285 		if (status != B_OK) {
1286 			T(Read(port, 0, status));
1287 			return status;
1288 		}
1289 	}
1290 
1291 	// determine tail & get the length of the message
1292 	port_message* message = port->messages.Head();
1293 	if (message == NULL) {
1294 		panic("port %" B_PRId32 ": no messages found\n", port->id);
1295 		return B_ERROR;
1296 	}
1297 
1298 	if (peekOnly) {
1299 		size_t size = copy_port_message(message, _code, buffer, bufferSize,
1300 			userCopy);
1301 
1302 		T(Read(port, message->code, size));
1303 
1304 		port->read_condition.NotifyOne();
1305 			// we only peeked, but didn't grab the message
1306 		return size;
1307 	}
1308 
1309 	port->messages.RemoveHead();
1310 	port->total_count++;
1311 	port->write_count++;
1312 	port->read_count--;
1313 
1314 	notify_port_select_events(port, B_EVENT_WRITE);
1315 	port->write_condition.NotifyOne();
1316 		// make one spot in queue available again for write
1317 
1318 	T(Read(id, port->read_count, port->write_count, message->code,
1319 		min_c(bufferSize, message->size)));
1320 
1321 	locker.Unlock();
1322 
1323 	size_t size = copy_port_message(message, _code, buffer, bufferSize,
1324 		userCopy);
1325 
1326 	put_port_message(message);
1327 	return size;
1328 }
1329 
1330 
1331 status_t
1332 write_port(port_id id, int32 msgCode, const void* buffer, size_t bufferSize)
1333 {
1334 	iovec vec = { (void*)buffer, bufferSize };
1335 
1336 	return writev_port_etc(id, msgCode, &vec, 1, bufferSize, 0, 0);
1337 }
1338 
1339 
1340 status_t
1341 write_port_etc(port_id id, int32 msgCode, const void* buffer,
1342 	size_t bufferSize, uint32 flags, bigtime_t timeout)
1343 {
1344 	iovec vec = { (void*)buffer, bufferSize };
1345 
1346 	return writev_port_etc(id, msgCode, &vec, 1, bufferSize, flags, timeout);
1347 }
1348 
1349 
1350 status_t
1351 writev_port_etc(port_id id, int32 msgCode, const iovec* msgVecs,
1352 	size_t vecCount, size_t bufferSize, uint32 flags, bigtime_t timeout)
1353 {
1354 	if (!sPortsActive || id < 0)
1355 		return B_BAD_PORT_ID;
1356 	if (bufferSize > PORT_MAX_MESSAGE_SIZE)
1357 		return B_BAD_VALUE;
1358 
1359 	// mask irrelevant flags (for acquire_sem() usage)
1360 	flags &= B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT | B_RELATIVE_TIMEOUT
1361 		| B_ABSOLUTE_TIMEOUT;
1362 	if ((flags & B_RELATIVE_TIMEOUT) != 0
1363 		&& timeout != B_INFINITE_TIMEOUT && timeout > 0) {
1364 		// Make the timeout absolute, since we have more than one step where
1365 		// we might have to wait
1366 		flags = (flags & ~B_RELATIVE_TIMEOUT) | B_ABSOLUTE_TIMEOUT;
1367 		timeout += system_time();
1368 	}
1369 
1370 	bool userCopy = (flags & PORT_FLAG_USE_USER_MEMCPY) > 0;
1371 
1372 	status_t status;
1373 	port_message* message = NULL;
1374 
1375 	// get the port
1376 	Port* port = get_locked_port(id);
1377 	if (port == NULL) {
1378 		TRACE(("write_port_etc: invalid port_id %ld\n", id));
1379 		return B_BAD_PORT_ID;
1380 	}
1381 	MutexLocker locker(port->lock, true);
1382 
1383 	if (is_port_closed(port)) {
1384 		TRACE(("write_port_etc: port %ld closed\n", id));
1385 		return B_BAD_PORT_ID;
1386 	}
1387 
1388 	if (port->write_count <= 0) {
1389 		if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0)
1390 			return B_WOULD_BLOCK;
1391 
1392 		port->write_count--;
1393 
1394 		// We need to block in order to wait for a free message slot
1395 		ConditionVariableEntry entry;
1396 		port->write_condition.Add(&entry);
1397 
1398 		locker.Unlock();
1399 
1400 		status = entry.Wait(flags, timeout);
1401 
1402 		// re-lock
1403 		Port* newPort = get_locked_port(id);
1404 		if (newPort == NULL) {
1405 			T(Write(id, 0, 0, 0, 0, B_BAD_PORT_ID));
1406 			return B_BAD_PORT_ID;
1407 		}
1408 		locker.SetTo(newPort->lock, true);
1409 
1410 		if (newPort != port || is_port_closed(port)) {
1411 			// the port is no longer there
1412 			T(Write(id, 0, 0, 0, 0, B_BAD_PORT_ID));
1413 			return B_BAD_PORT_ID;
1414 		}
1415 
1416 		if (status != B_OK)
1417 			goto error;
1418 	} else
1419 		port->write_count--;
1420 
1421 	status = get_port_message(msgCode, bufferSize, flags, timeout,
1422 		&message, *port);
1423 	if (status != B_OK) {
1424 		if (status == B_BAD_PORT_ID) {
1425 			// the port had to be unlocked and is now no longer there
1426 			T(Write(id, 0, 0, 0, 0, B_BAD_PORT_ID));
1427 			return B_BAD_PORT_ID;
1428 		}
1429 
1430 		goto error;
1431 	}
1432 
1433 	// sender credentials
1434 	message->sender = geteuid();
1435 	message->sender_group = getegid();
1436 	message->sender_team = team_get_current_team_id();
1437 
1438 	if (bufferSize > 0) {
1439 		size_t offset = 0;
1440 		for (uint32 i = 0; i < vecCount; i++) {
1441 			size_t bytes = msgVecs[i].iov_len;
1442 			if (bytes > bufferSize)
1443 				bytes = bufferSize;
1444 
1445 			if (userCopy) {
1446 				status_t status = user_memcpy(message->buffer + offset,
1447 					msgVecs[i].iov_base, bytes);
1448 				if (status != B_OK) {
1449 					put_port_message(message);
1450 					goto error;
1451 				}
1452 			} else
1453 				memcpy(message->buffer + offset, msgVecs[i].iov_base, bytes);
1454 
1455 			bufferSize -= bytes;
1456 			if (bufferSize == 0)
1457 				break;
1458 
1459 			offset += bytes;
1460 		}
1461 	}
1462 
1463 	port->messages.Add(message);
1464 	port->read_count++;
1465 
1466 	T(Write(id, port->read_count, port->write_count, message->code,
1467 		message->size, B_OK));
1468 
1469 	notify_port_select_events(port, B_EVENT_READ);
1470 	port->read_condition.NotifyOne();
1471 	return B_OK;
1472 
1473 error:
1474 	// Give up our slot in the queue again, and let someone else
1475 	// try and fail
1476 	T(Write(id, port->read_count, port->write_count, 0, 0, status));
1477 	port->write_count++;
1478 	notify_port_select_events(port, B_EVENT_WRITE);
1479 	port->write_condition.NotifyOne();
1480 
1481 	return status;
1482 }
1483 
1484 
1485 status_t
1486 set_port_owner(port_id id, team_id newTeamID)
1487 {
1488 	TRACE(("set_port_owner(id = %ld, team = %ld)\n", id, newTeamID));
1489 
1490 	if (id < 0)
1491 		return B_BAD_PORT_ID;
1492 
1493 	// get the new team
1494 	Team* team = Team::Get(newTeamID);
1495 	if (team == NULL)
1496 		return B_BAD_TEAM_ID;
1497 	BReference<Team> teamReference(team, true);
1498 
1499 	// get the port
1500 	MutexLocker portsLocker(sPortsLock);
1501 	Port* port = sPorts.Lookup(id);
1502 	if (port == NULL) {
1503 		TRACE(("set_port_owner: invalid port_id %ld\n", id));
1504 		return B_BAD_PORT_ID;
1505 	}
1506 	MutexLocker locker(port->lock);
1507 
1508 	// transfer ownership to other team
1509 	if (team->id != port->owner) {
1510 		list_remove_link(&port->team_link);
1511 		list_add_item(&team->port_list, &port->team_link);
1512 		port->owner = team->id;
1513 	}
1514 
1515 	T(OwnerChange(port, team->id, B_OK));
1516 	return B_OK;
1517 }
1518 
1519 
1520 //	#pragma mark - syscalls
1521 
1522 
1523 port_id
1524 _user_create_port(int32 queueLength, const char *userName)
1525 {
1526 	char name[B_OS_NAME_LENGTH];
1527 
1528 	if (userName == NULL)
1529 		return create_port(queueLength, NULL);
1530 
1531 	if (!IS_USER_ADDRESS(userName)
1532 		|| user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK)
1533 		return B_BAD_ADDRESS;
1534 
1535 	return create_port(queueLength, name);
1536 }
1537 
1538 
1539 status_t
1540 _user_close_port(port_id id)
1541 {
1542 	return close_port(id);
1543 }
1544 
1545 
1546 status_t
1547 _user_delete_port(port_id id)
1548 {
1549 	return delete_port(id);
1550 }
1551 
1552 
1553 port_id
1554 _user_find_port(const char *userName)
1555 {
1556 	char name[B_OS_NAME_LENGTH];
1557 
1558 	if (userName == NULL)
1559 		return B_BAD_VALUE;
1560 	if (!IS_USER_ADDRESS(userName)
1561 		|| user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK)
1562 		return B_BAD_ADDRESS;
1563 
1564 	return find_port(name);
1565 }
1566 
1567 
1568 status_t
1569 _user_get_port_info(port_id id, struct port_info *userInfo)
1570 {
1571 	struct port_info info;
1572 	status_t status;
1573 
1574 	if (userInfo == NULL)
1575 		return B_BAD_VALUE;
1576 	if (!IS_USER_ADDRESS(userInfo))
1577 		return B_BAD_ADDRESS;
1578 
1579 	status = get_port_info(id, &info);
1580 
1581 	// copy back to user space
1582 	if (status == B_OK
1583 		&& user_memcpy(userInfo, &info, sizeof(struct port_info)) < B_OK)
1584 		return B_BAD_ADDRESS;
1585 
1586 	return status;
1587 }
1588 
1589 
1590 status_t
1591 _user_get_next_port_info(team_id team, int32 *userCookie,
1592 	struct port_info *userInfo)
1593 {
1594 	struct port_info info;
1595 	status_t status;
1596 	int32 cookie;
1597 
1598 	if (userCookie == NULL || userInfo == NULL)
1599 		return B_BAD_VALUE;
1600 	if (!IS_USER_ADDRESS(userCookie) || !IS_USER_ADDRESS(userInfo)
1601 		|| user_memcpy(&cookie, userCookie, sizeof(int32)) < B_OK)
1602 		return B_BAD_ADDRESS;
1603 
1604 	status = get_next_port_info(team, &cookie, &info);
1605 
1606 	// copy back to user space
1607 	if (user_memcpy(userCookie, &cookie, sizeof(int32)) < B_OK
1608 		|| (status == B_OK && user_memcpy(userInfo, &info,
1609 				sizeof(struct port_info)) < B_OK))
1610 		return B_BAD_ADDRESS;
1611 
1612 	return status;
1613 }
1614 
1615 
1616 ssize_t
1617 _user_port_buffer_size_etc(port_id port, uint32 flags, bigtime_t timeout)
1618 {
1619 	syscall_restart_handle_timeout_pre(flags, timeout);
1620 
1621 	status_t status = port_buffer_size_etc(port, flags | B_CAN_INTERRUPT,
1622 		timeout);
1623 
1624 	return syscall_restart_handle_timeout_post(status, timeout);
1625 }
1626 
1627 
1628 ssize_t
1629 _user_port_count(port_id port)
1630 {
1631 	return port_count(port);
1632 }
1633 
1634 
1635 status_t
1636 _user_set_port_owner(port_id port, team_id team)
1637 {
1638 	return set_port_owner(port, team);
1639 }
1640 
1641 
1642 ssize_t
1643 _user_read_port_etc(port_id port, int32 *userCode, void *userBuffer,
1644 	size_t bufferSize, uint32 flags, bigtime_t timeout)
1645 {
1646 	int32 messageCode;
1647 	ssize_t	bytesRead;
1648 
1649 	syscall_restart_handle_timeout_pre(flags, timeout);
1650 
1651 	if (userBuffer == NULL && bufferSize != 0)
1652 		return B_BAD_VALUE;
1653 	if ((userCode != NULL && !IS_USER_ADDRESS(userCode))
1654 		|| (userBuffer != NULL && !IS_USER_ADDRESS(userBuffer)))
1655 		return B_BAD_ADDRESS;
1656 
1657 	bytesRead = read_port_etc(port, &messageCode, userBuffer, bufferSize,
1658 		flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT, timeout);
1659 
1660 	if (bytesRead >= 0 && userCode != NULL
1661 		&& user_memcpy(userCode, &messageCode, sizeof(int32)) < B_OK)
1662 		return B_BAD_ADDRESS;
1663 
1664 	return syscall_restart_handle_timeout_post(bytesRead, timeout);
1665 }
1666 
1667 
1668 status_t
1669 _user_write_port_etc(port_id port, int32 messageCode, const void *userBuffer,
1670 	size_t bufferSize, uint32 flags, bigtime_t timeout)
1671 {
1672 	iovec vec = { (void *)userBuffer, bufferSize };
1673 
1674 	syscall_restart_handle_timeout_pre(flags, timeout);
1675 
1676 	if (userBuffer == NULL && bufferSize != 0)
1677 		return B_BAD_VALUE;
1678 	if (userBuffer != NULL && !IS_USER_ADDRESS(userBuffer))
1679 		return B_BAD_ADDRESS;
1680 
1681 	status_t status = writev_port_etc(port, messageCode, &vec, 1, bufferSize,
1682 		flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT, timeout);
1683 
1684 	return syscall_restart_handle_timeout_post(status, timeout);
1685 }
1686 
1687 
1688 status_t
1689 _user_writev_port_etc(port_id port, int32 messageCode, const iovec *userVecs,
1690 	size_t vecCount, size_t bufferSize, uint32 flags, bigtime_t timeout)
1691 {
1692 	syscall_restart_handle_timeout_pre(flags, timeout);
1693 
1694 	if (userVecs == NULL && bufferSize != 0)
1695 		return B_BAD_VALUE;
1696 	if (userVecs != NULL && !IS_USER_ADDRESS(userVecs))
1697 		return B_BAD_ADDRESS;
1698 
1699 	iovec *vecs = NULL;
1700 	if (userVecs && vecCount != 0) {
1701 		vecs = (iovec*)malloc(sizeof(iovec) * vecCount);
1702 		if (vecs == NULL)
1703 			return B_NO_MEMORY;
1704 
1705 		if (user_memcpy(vecs, userVecs, sizeof(iovec) * vecCount) < B_OK) {
1706 			free(vecs);
1707 			return B_BAD_ADDRESS;
1708 		}
1709 	}
1710 
1711 	status_t status = writev_port_etc(port, messageCode, vecs, vecCount,
1712 		bufferSize, flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT,
1713 		timeout);
1714 
1715 	free(vecs);
1716 	return syscall_restart_handle_timeout_post(status, timeout);
1717 }
1718 
1719 
1720 status_t
1721 _user_get_port_message_info_etc(port_id port, port_message_info *userInfo,
1722 	size_t infoSize, uint32 flags, bigtime_t timeout)
1723 {
1724 	if (userInfo == NULL || infoSize != sizeof(port_message_info))
1725 		return B_BAD_VALUE;
1726 
1727 	syscall_restart_handle_timeout_pre(flags, timeout);
1728 
1729 	port_message_info info;
1730 	status_t error = _get_port_message_info_etc(port, &info, sizeof(info),
1731 		flags | B_CAN_INTERRUPT, timeout);
1732 
1733 	// copy info to userland
1734 	if (error == B_OK && (!IS_USER_ADDRESS(userInfo)
1735 			|| user_memcpy(userInfo, &info, sizeof(info)) != B_OK)) {
1736 		error = B_BAD_ADDRESS;
1737 	}
1738 
1739 	return syscall_restart_handle_timeout_post(error, timeout);
1740 }
1741