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