xref: /haiku/src/system/kernel/port.cpp (revision 0562493379cd52eb7103531f895f10bb8e77c085)
1 /*
2  * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de.
3  * Distributed under the terms of the MIT License.
4  *
5  * Copyright 2001, Mark-Jan Bastian. All rights reserved.
6  * Distributed under the terms of the NewOS License.
7  */
8 
9 /*!	Ports for IPC */
10 
11 #include <port.h>
12 
13 #include <ctype.h>
14 #include <iovec.h>
15 #include <stdlib.h>
16 #include <string.h>
17 
18 #include <OS.h>
19 
20 #include <arch/int.h>
21 #include <cbuf.h>
22 #include <kernel.h>
23 #include <Notifications.h>
24 #include <sem.h>
25 #include <syscall_restart.h>
26 #include <team.h>
27 #include <util/AutoLock.h>
28 #include <util/list.h>
29 #include <wait_for_objects.h>
30 
31 
32 //#define TRACE_PORTS
33 #ifdef TRACE_PORTS
34 #	define TRACE(x) dprintf x
35 #else
36 #	define TRACE(x)
37 #endif
38 
39 
40 typedef struct port_msg {
41 	list_link	link;
42 	int32		code;
43 	cbuf		*buffer_chain;
44 	size_t		size;
45 	uid_t		sender;
46 	gid_t		sender_group;
47 	team_id		sender_team;
48 } port_msg;
49 
50 struct port_entry {
51 	port_id 	id;
52 	team_id 	owner;
53 	int32 		capacity;
54 	spinlock	lock;
55 	const char	*name;
56 	sem_id		read_sem;
57 	sem_id		write_sem;
58 	int32		total_count;	// messages read from port since creation
59 	select_info	*select_infos;
60 	struct list	msg_queue;
61 };
62 
63 class PortNotificationService : public DefaultNotificationService {
64 public:
65 							PortNotificationService();
66 
67 			void			Notify(uint32 opcode, port_id team);
68 
69 protected:
70 	virtual	status_t		_ToFlags(const KMessage& eventSpecifier,
71 								uint32& flags);
72 };
73 
74 #define MAX_QUEUE_LENGTH 4096
75 #define PORT_MAX_MESSAGE_SIZE (256 * 1024)
76 
77 // sMaxPorts must be power of 2
78 static int32 sMaxPorts = 4096;
79 static int32 sUsedPorts = 0;
80 
81 static struct port_entry *sPorts = NULL;
82 static area_id sPortArea = 0;
83 static bool sPortsActive = false;
84 static port_id sNextPort = 1;
85 static int32 sFirstFreeSlot = 1;
86 
87 static PortNotificationService sNotificationService;
88 
89 static spinlock sPortSpinlock = B_SPINLOCK_INITIALIZER;
90 
91 #define GRAB_PORT_LIST_LOCK() acquire_spinlock(&sPortSpinlock)
92 #define RELEASE_PORT_LIST_LOCK() release_spinlock(&sPortSpinlock)
93 #define GRAB_PORT_LOCK(s) acquire_spinlock(&(s).lock)
94 #define RELEASE_PORT_LOCK(s) release_spinlock(&(s).lock)
95 
96 
97 //	#pragma mark - TeamNotificationService
98 
99 
100 PortNotificationService::PortNotificationService()
101 	: DefaultNotificationService("ports")
102 {
103 }
104 
105 
106 void
107 PortNotificationService::Notify(uint32 opcode, port_id port)
108 {
109 	char eventBuffer[64];
110 	KMessage event;
111 	event.SetTo(eventBuffer, sizeof(eventBuffer), PORT_MONITOR);
112 	event.AddInt32("opcode", opcode);
113 	event.AddInt32("port", port);
114 
115 	DefaultNotificationService::Notify(event, ~0U);
116 }
117 
118 
119 status_t
120 PortNotificationService::_ToFlags(const KMessage& eventSpecifier, uint32& flags)
121 {
122 	flags = ~0U;
123 	return B_OK;
124 }
125 
126 
127 //	#pragma mark -
128 
129 
130 static int
131 dump_port_list(int argc, char **argv)
132 {
133 	const char *name = NULL;
134 	team_id owner = -1;
135 	int32 i;
136 
137 	if (argc > 2) {
138 		if (!strcmp(argv[1], "team") || !strcmp(argv[1], "owner"))
139 			owner = strtoul(argv[2], NULL, 0);
140 		else if (!strcmp(argv[1], "name"))
141 			name = argv[2];
142 	} else if (argc > 1)
143 		owner = strtoul(argv[1], NULL, 0);
144 
145 	kprintf("port             id  cap  r-sem  r-cnt  w-sem  w-cnt    total   team  name\n");
146 
147 	for (i = 0; i < sMaxPorts; i++) {
148 		struct port_entry *port = &sPorts[i];
149 		if (port->id < 0
150 			|| (owner != -1 && port->owner != owner)
151 			|| (name != NULL && strstr(port->name, name) == NULL))
152 			continue;
153 
154 		int32 readCount, writeCount;
155 		get_sem_count(port->read_sem, &readCount);
156 		get_sem_count(port->write_sem, &writeCount);
157 		kprintf("%p %8ld %4ld %6ld %6ld %6ld %6ld %8ld %6ld  %s\n", port,
158 			port->id, port->capacity, port->read_sem, readCount,
159 			port->write_sem, writeCount, port->total_count, port->owner,
160 			port->name);
161 	}
162 	return 0;
163 }
164 
165 
166 static void
167 _dump_port_info(struct port_entry *port)
168 {
169 	int32 count;
170 
171 	kprintf("PORT: %p\n", port);
172 	kprintf(" id:              %ld\n", port->id);
173 	kprintf(" name:            \"%s\"\n", port->name);
174 	kprintf(" owner:           %ld\n", port->owner);
175 	kprintf(" capacity:        %ld\n", port->capacity);
176 	kprintf(" read_sem:        %ld\n", port->read_sem);
177 	kprintf(" write_sem:       %ld\n", port->write_sem);
178  	get_sem_count(port->read_sem, &count);
179  	kprintf(" read_sem count:  %ld\n", count);
180  	get_sem_count(port->write_sem, &count);
181 	kprintf(" write_sem count: %ld\n", count);
182 	kprintf(" total count:     %ld\n", port->total_count);
183 
184 	set_debug_variable("_port", (addr_t)port);
185 	set_debug_variable("_portID", port->id);
186 	set_debug_variable("_owner", port->owner);
187 	set_debug_variable("_readSem", port->read_sem);
188 	set_debug_variable("_writeSem", port->write_sem);
189 }
190 
191 
192 static int
193 dump_port_info(int argc, char **argv)
194 {
195 	const char *name = NULL;
196 	sem_id sem = -1;
197 	int i;
198 
199 	if (argc < 2) {
200 		print_debugger_command_usage(argv[0]);
201 		return 0;
202 	}
203 
204 	if (argc > 2) {
205 		if (!strcmp(argv[1], "address")) {
206 			_dump_port_info((struct port_entry *)strtoul(argv[2], NULL, 0));
207 			return 0;
208 		} else if (!strcmp(argv[1], "sem"))
209 			sem = strtoul(argv[2], NULL, 0);
210 		else if (!strcmp(argv[1], "name"))
211 			name = argv[2];
212 	} else if (isdigit(argv[1][0])) {
213 		// if the argument looks like a number, treat it as such
214 		uint32 num = strtoul(argv[1], NULL, 0);
215 		uint32 slot = num % sMaxPorts;
216 		if (sPorts[slot].id != (int)num) {
217 			kprintf("port %ld (%#lx) doesn't exist!\n", num, num);
218 			return 0;
219 		}
220 		_dump_port_info(&sPorts[slot]);
221 		return 0;
222 	} else
223 		name = argv[1];
224 
225 	// walk through the ports list, trying to match name
226 	for (i = 0; i < sMaxPorts; i++) {
227 		if ((name != NULL && sPorts[i].name != NULL
228 				&& !strcmp(name, sPorts[i].name))
229 			|| (sem != -1 && (sPorts[i].read_sem == sem
230 				|| sPorts[i].write_sem == sem))) {
231 			_dump_port_info(&sPorts[i]);
232 			return 0;
233 		}
234 	}
235 
236 	return 0;
237 }
238 
239 
240 static void
241 notify_port_select_events(int slot, uint16 events)
242 {
243 	if (sPorts[slot].select_infos)
244 		notify_select_events_list(sPorts[slot].select_infos, events);
245 }
246 
247 
248 static void
249 put_port_msg(port_msg *msg)
250 {
251 	cbuf_free_chain(msg->buffer_chain);
252 	free(msg);
253 }
254 
255 
256 static port_msg *
257 get_port_msg(int32 code, size_t bufferSize)
258 {
259 	// ToDo: investigate preallocation of port_msgs (or use a slab allocator)
260 	cbuf *bufferChain = NULL;
261 
262 	port_msg *msg = (port_msg *)malloc(sizeof(port_msg));
263 	if (msg == NULL)
264 		return NULL;
265 
266 	if (bufferSize > 0) {
267 		bufferChain = cbuf_get_chain(bufferSize);
268 		if (bufferChain == NULL) {
269 			free(msg);
270 			return NULL;
271 		}
272 	}
273 
274 	msg->code = code;
275 	msg->buffer_chain = bufferChain;
276 	msg->size = bufferSize;
277 	return msg;
278 }
279 
280 
281 /*!	You need to own the port's lock when calling this function */
282 static bool
283 is_port_closed(int32 slot)
284 {
285 	return sPorts[slot].capacity == 0;
286 }
287 
288 
289 /*!	Fills the port_info structure with information from the specified
290 	port.
291 	The port lock must be held when called.
292 */
293 static void
294 fill_port_info(struct port_entry *port, port_info *info, size_t size)
295 {
296 	int32 count;
297 
298 	info->port = port->id;
299 	info->team = port->owner;
300 	info->capacity = port->capacity;
301 
302 	get_sem_count(port->read_sem, &count);
303 	if (count < 0)
304 		count = 0;
305 
306 	info->queue_count = count;
307 	info->total_count = port->total_count;
308 
309 	strlcpy(info->name, port->name, B_OS_NAME_LENGTH);
310 }
311 
312 
313 //	#pragma mark - private kernel API
314 
315 
316 /*! This function cycles through the ports table, deleting all
317 	the ports that are owned by the passed team_id
318 */
319 int
320 delete_owned_ports(team_id owner)
321 {
322 	// ToDo: investigate maintaining a list of ports in the team
323 	//	to make this simpler and more efficient.
324 	cpu_status state;
325 	int i;
326 	int count = 0;
327 
328 	TRACE(("delete_owned_ports(owner = %ld)\n", owner));
329 
330 	if (!sPortsActive)
331 		return B_BAD_PORT_ID;
332 
333 	state = disable_interrupts();
334 	GRAB_PORT_LIST_LOCK();
335 
336 	for (i = 0; i < sMaxPorts; i++) {
337 		if (sPorts[i].id != -1 && sPorts[i].owner == owner) {
338 			port_id id = sPorts[i].id;
339 
340 			RELEASE_PORT_LIST_LOCK();
341 			restore_interrupts(state);
342 
343 			delete_port(id);
344 			count++;
345 
346 			state = disable_interrupts();
347 			GRAB_PORT_LIST_LOCK();
348 		}
349 	}
350 
351 	RELEASE_PORT_LIST_LOCK();
352 	restore_interrupts(state);
353 
354 	return count;
355 }
356 
357 
358 int32
359 port_max_ports(void)
360 {
361 	return sMaxPorts;
362 }
363 
364 
365 int32
366 port_used_ports(void)
367 {
368 	return sUsedPorts;
369 }
370 
371 
372 status_t
373 port_init(kernel_args *args)
374 {
375 	size_t size = sizeof(struct port_entry) * sMaxPorts;
376 	int32 i;
377 
378 	// create and initialize ports table
379 	sPortArea = create_area("port_table", (void **)&sPorts, B_ANY_KERNEL_ADDRESS,
380 		size, B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
381 	if (sPortArea < 0) {
382 		panic("unable to allocate kernel port table!\n");
383 		return sPortArea;
384 	}
385 
386 	// ToDo: investigate preallocating a list of port_msgs to
387 	//	speed up actual message sending/receiving, a slab allocator
388 	//	might do it as well, though :-)
389 
390 	memset(sPorts, 0, size);
391 	for (i = 0; i < sMaxPorts; i++)
392 		sPorts[i].id = -1;
393 
394 	// add debugger commands
395 	add_debugger_command_etc("ports", &dump_port_list,
396 		"Dump a list of all active ports (for team, with name, etc.)",
397 		"[ ([ \"team\" | \"owner\" ] <team>) | (\"name\" <name>) ]\n"
398 		"Prints a list of all active ports meeting the given\n"
399 		"requirement. If no argument is given, all ports are listed.\n"
400 		"  <team>             - The team owning the ports.\n"
401 		"  <name>             - Part of the name of the ports.\n", 0);
402 	add_debugger_command_etc("port", &dump_port_info,
403 		"Dump info about a particular port",
404 		"([ \"address\" ] <address>) | ([ \"name\" ] <name>) "
405 			"| (\"sem\" <sem>)\n"
406 		"Prints info about the specified port.\n"
407 		"  <address>  - Pointer to the port structure.\n"
408 		"  <name>     - Name of the port.\n"
409 		"  <sem>      - ID of the port's read or write semaphore.\n", 0);
410 
411 	new(&sNotificationService) PortNotificationService();
412 	sPortsActive = true;
413 	return B_OK;
414 }
415 
416 
417 //	#pragma mark - public kernel API
418 
419 
420 port_id
421 create_port(int32 queueLength, const char *name)
422 {
423 	cpu_status state;
424 	char nameBuffer[B_OS_NAME_LENGTH];
425 	sem_id readSem, writeSem;
426 	status_t status;
427 	team_id	owner;
428 	int32 slot;
429 
430 	TRACE(("create_port(queueLength = %ld, name = \"%s\")\n", queueLength,
431 		name));
432 
433 	if (!sPortsActive)
434 		return B_BAD_PORT_ID;
435 
436 	// check queue length
437 	if (queueLength < 1
438 		|| queueLength > MAX_QUEUE_LENGTH)
439 		return B_BAD_VALUE;
440 
441 	// check early on if there are any free port slots to use
442 	if (atomic_add(&sUsedPorts, 1) >= sMaxPorts) {
443 		status = B_NO_MORE_PORTS;
444 		goto err1;
445 	}
446 
447 	// check & dup name
448 	if (name == NULL)
449 		name = "unnamed port";
450 
451 	// ToDo: we could save the memory and use the semaphore name only instead
452 	strlcpy(nameBuffer, name, B_OS_NAME_LENGTH);
453 	name = strdup(nameBuffer);
454 	if (name == NULL) {
455 		status = B_NO_MEMORY;
456 		goto err1;
457 	}
458 
459 	// create read sem with owner set to -1
460 	// ToDo: should be B_SYSTEM_TEAM
461 	readSem = create_sem_etc(0, name, -1);
462 	if (readSem < B_OK) {
463 		status = readSem;
464 		goto err2;
465 	}
466 
467 	// create write sem
468 	writeSem = create_sem_etc(queueLength, name, -1);
469 	if (writeSem < B_OK) {
470 		status = writeSem;
471 		goto err3;
472 	}
473 
474 	owner = team_get_current_team_id();
475 
476 	state = disable_interrupts();
477 	GRAB_PORT_LIST_LOCK();
478 
479 	// find the first empty spot
480 	for (slot = 0; slot < sMaxPorts; slot++) {
481 		int32 i = (slot + sFirstFreeSlot) % sMaxPorts;
482 
483 		if (sPorts[i].id == -1) {
484 			port_id id;
485 
486 			// make the port_id be a multiple of the slot it's in
487 			if (i >= sNextPort % sMaxPorts)
488 				sNextPort += i - sNextPort % sMaxPorts;
489 			else
490 				sNextPort += sMaxPorts - (sNextPort % sMaxPorts - i);
491 			sFirstFreeSlot = slot + 1;
492 
493 			GRAB_PORT_LOCK(sPorts[i]);
494 			sPorts[i].id = sNextPort++;
495 			RELEASE_PORT_LIST_LOCK();
496 
497 			sPorts[i].capacity = queueLength;
498 			sPorts[i].owner = owner;
499 			sPorts[i].name = name;
500 
501 			sPorts[i].read_sem	= readSem;
502 			sPorts[i].write_sem	= writeSem;
503 
504 			list_init(&sPorts[i].msg_queue);
505 			sPorts[i].total_count = 0;
506 			sPorts[i].select_infos = NULL;
507 			id = sPorts[i].id;
508 
509 			RELEASE_PORT_LOCK(sPorts[i]);
510 			restore_interrupts(state);
511 
512 			TRACE(("create_port() done: port created %ld\n", id));
513 
514 			sNotificationService.Notify(PORT_ADDED, id);
515 			return id;
516 		}
517 	}
518 
519 	// not enough ports...
520 
521 	// TODO: due to sUsedPorts, this cannot happen anymore - as
522 	//		long as sMaxPorts stays constant over the kernel run
523 	//		time (which it should be). IOW we could simply panic()
524 	//		here.
525 
526 	RELEASE_PORT_LIST_LOCK();
527 	restore_interrupts(state);
528 
529 	status = B_NO_MORE_PORTS;
530 
531 	delete_sem(writeSem);
532 err3:
533 	delete_sem(readSem);
534 err2:
535 	free((char *)name);
536 err1:
537 	atomic_add(&sUsedPorts, -1);
538 
539 	return status;
540 }
541 
542 
543 status_t
544 close_port(port_id id)
545 {
546 	sem_id readSem, writeSem;
547 	cpu_status state;
548 	int32 slot;
549 
550 	TRACE(("close_port(id = %ld)\n", id));
551 
552 	if (!sPortsActive || id < 0)
553 		return B_BAD_PORT_ID;
554 
555 	slot = id % sMaxPorts;
556 
557 	// walk through the sem list, trying to match name
558 	state = disable_interrupts();
559 	GRAB_PORT_LOCK(sPorts[slot]);
560 
561 	if (sPorts[slot].id != id) {
562 		RELEASE_PORT_LOCK(sPorts[slot]);
563 		restore_interrupts(state);
564 		TRACE(("close_port: invalid port_id %ld\n", id));
565 		return B_BAD_PORT_ID;
566 	}
567 
568 	// mark port to disable writing - deleting the semaphores will
569 	// wake up waiting read/writes
570 	sPorts[slot].capacity = 0;
571 	readSem = sPorts[slot].read_sem;
572 	writeSem = sPorts[slot].write_sem;
573 
574 	notify_port_select_events(slot, B_EVENT_INVALID);
575 	sPorts[slot].select_infos = NULL;
576 
577 	RELEASE_PORT_LOCK(sPorts[slot]);
578 	restore_interrupts(state);
579 
580 	delete_sem(readSem);
581 	delete_sem(writeSem);
582 
583 	return B_NO_ERROR;
584 }
585 
586 
587 status_t
588 delete_port(port_id id)
589 {
590 	cpu_status state;
591 	sem_id readSem, writeSem;
592 	const char *name;
593 	struct list list;
594 	port_msg *msg;
595 	int32 slot;
596 
597 	TRACE(("delete_port(id = %ld)\n", id));
598 
599 	if (!sPortsActive || id < 0)
600 		return B_BAD_PORT_ID;
601 
602 	slot = id % sMaxPorts;
603 
604 	state = disable_interrupts();
605 	GRAB_PORT_LOCK(sPorts[slot]);
606 
607 	if (sPorts[slot].id != id) {
608 		RELEASE_PORT_LOCK(sPorts[slot]);
609 		restore_interrupts(state);
610 
611 		TRACE(("delete_port: invalid port_id %ld\n", id));
612 		return B_BAD_PORT_ID;
613 	}
614 
615 	/* mark port as invalid */
616 	sPorts[slot].id	= -1;
617 	name = sPorts[slot].name;
618 	readSem = sPorts[slot].read_sem;
619 	writeSem = sPorts[slot].write_sem;
620 	sPorts[slot].name = NULL;
621 	list_move_to_list(&sPorts[slot].msg_queue, &list);
622 
623 	notify_port_select_events(slot, B_EVENT_INVALID);
624 	sPorts[slot].select_infos = NULL;
625 
626 	RELEASE_PORT_LOCK(sPorts[slot]);
627 
628 	// update the first free slot hint in the array
629 	GRAB_PORT_LIST_LOCK();
630 	if (slot < sFirstFreeSlot)
631 		sFirstFreeSlot = slot;
632 	RELEASE_PORT_LIST_LOCK();
633 
634 	restore_interrupts(state);
635 
636 	atomic_add(&sUsedPorts, -1);
637 
638 	// free the queue
639 	while ((msg = (port_msg *)list_remove_head_item(&list)) != NULL) {
640 		put_port_msg(msg);
641 	}
642 
643 	free((char *)name);
644 
645 	// release the threads that were blocking on this port by deleting the sem
646 	// read_port() will see the B_BAD_SEM_ID acq_sem() return value, and act accordingly
647 	delete_sem(readSem);
648 	delete_sem(writeSem);
649 	sNotificationService.Notify(PORT_REMOVED, id);
650 
651 	return B_OK;
652 }
653 
654 
655 status_t
656 select_port(int32 id, struct select_info *info, bool kernel)
657 {
658 	cpu_status state;
659 	int32 slot;
660 	status_t error = B_OK;
661 
662 	if (id < 0)
663 		return B_BAD_PORT_ID;
664 
665 	slot = id % sMaxPorts;
666 
667 	state = disable_interrupts();
668 	GRAB_PORT_LOCK(sPorts[slot]);
669 
670 	if (sPorts[slot].id != id || is_port_closed(slot)) {
671 		// bad port ID
672 		error = B_BAD_SEM_ID;
673 	} else if (!kernel && sPorts[slot].owner == team_get_kernel_team_id()) {
674 		// kernel port, but call from userland
675 		error = B_NOT_ALLOWED;
676 	} else {
677 		info->selected_events &= B_EVENT_READ | B_EVENT_WRITE | B_EVENT_INVALID;
678 
679 		if (info->selected_events != 0) {
680 			uint16 events = 0;
681 			int32 writeCount = 0;
682 
683 			info->next = sPorts[slot].select_infos;
684 			sPorts[slot].select_infos = info;
685 
686 			// check for events
687 			if ((info->selected_events & B_EVENT_READ) != 0
688 				&& !list_is_empty(&sPorts[slot].msg_queue)) {
689 				events |= B_EVENT_READ;
690 			}
691 
692 			if (get_sem_count(sPorts[slot].write_sem, &writeCount) == B_OK
693 				&& writeCount > 0) {
694 				events |= B_EVENT_WRITE;
695 			}
696 
697 			if (events != 0)
698 				notify_select_events(info, events);
699 		}
700 	}
701 
702 	RELEASE_PORT_LOCK(sPorts[slot]);
703 	restore_interrupts(state);
704 
705 	return error;
706 }
707 
708 
709 status_t
710 deselect_port(int32 id, struct select_info *info, bool kernel)
711 {
712 	cpu_status state;
713 	int32 slot;
714 
715 	if (id < 0)
716 		return B_BAD_PORT_ID;
717 
718 	if (info->selected_events == 0)
719 		return B_OK;
720 
721 	slot = id % sMaxPorts;
722 
723 	state = disable_interrupts();
724 	GRAB_PORT_LOCK(sPorts[slot]);
725 
726 	if (sPorts[slot].id == id) {
727 		select_info** infoLocation = &sPorts[slot].select_infos;
728 		while (*infoLocation != NULL && *infoLocation != info)
729 			infoLocation = &(*infoLocation)->next;
730 
731 		if (*infoLocation == info)
732 			*infoLocation = info->next;
733 	}
734 
735 	RELEASE_PORT_LOCK(sPorts[slot]);
736 	restore_interrupts(state);
737 
738 	return B_OK;
739 }
740 
741 
742 port_id
743 find_port(const char *name)
744 {
745 	port_id portFound = B_NAME_NOT_FOUND;
746 	cpu_status state;
747 	int32 i;
748 
749 	TRACE(("find_port(name = \"%s\")\n", name));
750 
751 	if (!sPortsActive)
752 		return B_NAME_NOT_FOUND;
753 	if (name == NULL)
754 		return B_BAD_VALUE;
755 
756 	// Since we have to check every single port, and we don't
757 	// care if it goes away at any point, we're only grabbing
758 	// the port lock in question, not the port list lock
759 
760 	// loop over list
761 	for (i = 0; i < sMaxPorts && portFound < B_OK; i++) {
762 		// lock every individual port before comparing
763 		state = disable_interrupts();
764 		GRAB_PORT_LOCK(sPorts[i]);
765 
766 		if (sPorts[i].id >= 0 && !strcmp(name, sPorts[i].name))
767 			portFound = sPorts[i].id;
768 
769 		RELEASE_PORT_LOCK(sPorts[i]);
770 		restore_interrupts(state);
771 	}
772 
773 	return portFound;
774 }
775 
776 
777 status_t
778 _get_port_info(port_id id, port_info *info, size_t size)
779 {
780 	cpu_status state;
781 	int slot;
782 
783 	TRACE(("get_port_info(id = %ld)\n", id));
784 
785 	if (info == NULL || size != sizeof(port_info))
786 		return B_BAD_VALUE;
787 	if (!sPortsActive || id < 0)
788 		return B_BAD_PORT_ID;
789 
790 	slot = id % sMaxPorts;
791 
792 	state = disable_interrupts();
793 	GRAB_PORT_LOCK(sPorts[slot]);
794 
795 	if (sPorts[slot].id != id || sPorts[slot].capacity == 0) {
796 		RELEASE_PORT_LOCK(sPorts[slot]);
797 		restore_interrupts(state);
798 		TRACE(("get_port_info: invalid port_id %ld\n", id));
799 		return B_BAD_PORT_ID;
800 	}
801 
802 	// fill a port_info struct with info
803 	fill_port_info(&sPorts[slot], info, size);
804 
805 	RELEASE_PORT_LOCK(sPorts[slot]);
806 	restore_interrupts(state);
807 
808 	return B_OK;
809 }
810 
811 
812 status_t
813 _get_next_port_info(team_id team, int32 *_cookie, struct port_info *info, size_t size)
814 {
815 	cpu_status state;
816 	int slot;
817 
818 	TRACE(("get_next_port_info(team = %ld)\n", team));
819 
820 	if (info == NULL || size != sizeof(port_info) || _cookie == NULL || team < B_OK)
821 		return B_BAD_VALUE;
822 	if (!sPortsActive)
823 		return B_BAD_PORT_ID;
824 
825 	slot = *_cookie;
826 	if (slot >= sMaxPorts)
827 		return B_BAD_PORT_ID;
828 
829 	if (team == B_CURRENT_TEAM)
830 		team = team_get_current_team_id();
831 
832 	info->port = -1; // used as found flag
833 
834 	// spinlock
835 	state = disable_interrupts();
836 	GRAB_PORT_LIST_LOCK();
837 
838 	while (slot < sMaxPorts) {
839 		GRAB_PORT_LOCK(sPorts[slot]);
840 		if (sPorts[slot].id != -1 && sPorts[slot].capacity != 0 && sPorts[slot].owner == team) {
841 			// found one!
842 			fill_port_info(&sPorts[slot], info, size);
843 
844 			RELEASE_PORT_LOCK(sPorts[slot]);
845 			slot++;
846 			break;
847 		}
848 		RELEASE_PORT_LOCK(sPorts[slot]);
849 		slot++;
850 	}
851 	RELEASE_PORT_LIST_LOCK();
852 	restore_interrupts(state);
853 
854 	if (info->port == -1)
855 		return B_BAD_PORT_ID;
856 
857 	*_cookie = slot;
858 	return B_NO_ERROR;
859 }
860 
861 
862 ssize_t
863 port_buffer_size(port_id id)
864 {
865 	return port_buffer_size_etc(id, 0, 0);
866 }
867 
868 
869 ssize_t
870 port_buffer_size_etc(port_id id, uint32 flags, bigtime_t timeout)
871 {
872 	port_message_info info;
873 	status_t error = get_port_message_info_etc(id, &info, flags, timeout);
874 	return error != B_OK ? error : info.size;
875 }
876 
877 status_t
878 _get_port_message_info_etc(port_id id, port_message_info *info,
879 	size_t infoSize, uint32 flags, bigtime_t timeout)
880 {
881 	if (info == NULL || infoSize != sizeof(port_message_info))
882 		return B_BAD_VALUE;
883 
884 	cpu_status state;
885 	sem_id cachedSem;
886 	status_t status;
887 	port_msg *msg;
888 	int32 slot;
889 
890 	if (!sPortsActive || id < 0)
891 		return B_BAD_PORT_ID;
892 
893 	slot = id % sMaxPorts;
894 
895 	state = disable_interrupts();
896 	GRAB_PORT_LOCK(sPorts[slot]);
897 
898 	if (sPorts[slot].id != id
899 		|| (is_port_closed(slot) && list_is_empty(&sPorts[slot].msg_queue))) {
900 		RELEASE_PORT_LOCK(sPorts[slot]);
901 		restore_interrupts(state);
902 		TRACE(("port_buffer_size_etc(): %s port %ld\n",
903 			sPorts[slot].id == id ? "closed" : "invalid", id));
904 		return B_BAD_PORT_ID;
905 	}
906 
907 	cachedSem = sPorts[slot].read_sem;
908 
909 	RELEASE_PORT_LOCK(sPorts[slot]);
910 	restore_interrupts(state);
911 
912 	// block if no message, or, if B_TIMEOUT flag set, block with timeout
913 
914 	status = acquire_sem_etc(cachedSem, 1, flags, timeout);
915 	if (status != B_OK && status != B_BAD_SEM_ID)
916 		return status;
917 
918 	// in case of B_BAD_SEM_ID, the port might have been closed but not yet
919 	// deleted, ie. there could still be messages waiting for us
920 
921 	state = disable_interrupts();
922 	GRAB_PORT_LOCK(sPorts[slot]);
923 
924 	if (sPorts[slot].id != id) {
925 		// the port is no longer there
926 		RELEASE_PORT_LOCK(sPorts[slot]);
927 		restore_interrupts(state);
928 		return B_BAD_PORT_ID;
929 	}
930 
931 	// determine tail & get the length of the message
932 	status_t error = B_OK;
933 	msg = (port_msg*)list_get_first_item(&sPorts[slot].msg_queue);
934 	if (msg == NULL) {
935 		if (status == B_OK)
936 			panic("port %ld: no messages found\n", sPorts[slot].id);
937 
938 		error = B_BAD_PORT_ID;
939 	} else {
940 		info->size = msg->size;
941 		info->sender = msg->sender;
942 		info->sender_group = msg->sender_group;
943 		info->sender_team = msg->sender_team;
944 	}
945 
946 	RELEASE_PORT_LOCK(sPorts[slot]);
947 	restore_interrupts(state);
948 
949 	// restore read_sem, as we haven't read from the port
950 	release_sem(cachedSem);
951 
952 	// return length of item at end of queue
953 	return error;
954 }
955 
956 
957 ssize_t
958 port_count(port_id id)
959 {
960 	cpu_status state;
961 	int32 count = 0;
962 	int32 slot;
963 
964 	if (!sPortsActive || id < 0)
965 		return B_BAD_PORT_ID;
966 
967 	slot = id % sMaxPorts;
968 
969 	state = disable_interrupts();
970 	GRAB_PORT_LOCK(sPorts[slot]);
971 
972 	if (sPorts[slot].id != id) {
973 		RELEASE_PORT_LOCK(sPorts[slot]);
974 		restore_interrupts(state);
975 		TRACE(("port_count: invalid port_id %ld\n", id));
976 		return B_BAD_PORT_ID;
977 	}
978 
979 	if (get_sem_count(sPorts[slot].read_sem, &count) == B_OK) {
980 		// do not return negative numbers
981 		if (count < 0)
982 			count = 0;
983 	} else {
984 		// the port might have been closed - we need to actually count the messages
985 		void *message = NULL;
986 		while ((message = list_get_next_item(&sPorts[slot].msg_queue, message)) != NULL) {
987 			count++;
988 		}
989 	}
990 
991 	RELEASE_PORT_LOCK(sPorts[slot]);
992 	restore_interrupts(state);
993 
994 	// return count of messages
995 	return count;
996 }
997 
998 
999 ssize_t
1000 read_port(port_id port, int32 *msgCode, void *msgBuffer, size_t bufferSize)
1001 {
1002 	return read_port_etc(port, msgCode, msgBuffer, bufferSize, 0, 0);
1003 }
1004 
1005 
1006 ssize_t
1007 read_port_etc(port_id id, int32 *_msgCode, void *msgBuffer, size_t bufferSize,
1008 	uint32 flags, bigtime_t timeout)
1009 {
1010 	cpu_status state;
1011 	sem_id cachedSem;
1012 	status_t status;
1013 	bool userCopy = (flags & PORT_FLAG_USE_USER_MEMCPY) != 0;
1014 	bool peekOnly = !userCopy && (flags & B_PEEK_PORT_MESSAGE) != 0;
1015 	port_msg *msg;
1016 	size_t size;
1017 	int slot;
1018 
1019 	if (!sPortsActive || id < 0)
1020 		return B_BAD_PORT_ID;
1021 
1022 	if ((msgBuffer == NULL && bufferSize > 0)
1023 		|| timeout < 0)
1024 		return B_BAD_VALUE;
1025 
1026 	flags = flags & (B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT
1027 				| B_RELATIVE_TIMEOUT | B_ABSOLUTE_TIMEOUT);
1028 	slot = id % sMaxPorts;
1029 
1030 	state = disable_interrupts();
1031 	GRAB_PORT_LOCK(sPorts[slot]);
1032 
1033 	if (sPorts[slot].id != id
1034 		|| (is_port_closed(slot) && list_is_empty(&sPorts[slot].msg_queue))) {
1035 		RELEASE_PORT_LOCK(sPorts[slot]);
1036 		restore_interrupts(state);
1037 		TRACE(("read_port_etc(): %s port %ld\n",
1038 			sPorts[slot].id == id ? "closed" : "invalid", id));
1039 		return B_BAD_PORT_ID;
1040 	}
1041 	// store sem_id in local variable
1042 	cachedSem = sPorts[slot].read_sem;
1043 
1044 	// unlock port && enable ints/
1045 	RELEASE_PORT_LOCK(sPorts[slot]);
1046 	restore_interrupts(state);
1047 
1048 	status = acquire_sem_etc(cachedSem, 1, flags, timeout);
1049 		// get 1 entry from the queue, block if needed
1050 
1051 	if (status != B_OK && status != B_BAD_SEM_ID)
1052 		return status;
1053 
1054 	// in case of B_BAD_SEM_ID, the port might have been closed but not yet
1055 	// deleted, ie. there could still be messages waiting for us
1056 
1057 	state = disable_interrupts();
1058 	GRAB_PORT_LOCK(sPorts[slot]);
1059 
1060 	// first, let's check if the port is still alive
1061 	if (sPorts[slot].id == -1) {
1062 		// the port has been deleted in the meantime
1063 		RELEASE_PORT_LOCK(sPorts[slot]);
1064 		restore_interrupts(state);
1065 		return B_BAD_PORT_ID;
1066 	}
1067 
1068 	msg = (port_msg*)list_get_first_item(&sPorts[slot].msg_queue);
1069 	if (msg == NULL) {
1070 		if (status == B_OK)
1071 			panic("port %ld: no messages found", sPorts[slot].id);
1072 
1073 		// the port has obviously been closed, but no messages are left anymore
1074 		RELEASE_PORT_LOCK(sPorts[slot]);
1075 		restore_interrupts(state);
1076 		return B_BAD_PORT_ID;
1077 	}
1078 
1079 	if (peekOnly) {
1080 		size = min_c(bufferSize, msg->size);
1081 		if (_msgCode != NULL)
1082 			*_msgCode = msg->code;
1083 		if (size > 0)
1084 			cbuf_memcpy_from_chain(msgBuffer, msg->buffer_chain, 0, size);
1085 		RELEASE_PORT_LOCK(sPorts[slot]);
1086 		restore_interrupts(state);
1087 		release_sem_etc(cachedSem, 1, B_DO_NOT_RESCHEDULE);
1088 			// we only peeked, but didn't grab the message
1089 		return size;
1090 	}
1091 
1092 	list_remove_link(msg);
1093 
1094 	sPorts[slot].total_count++;
1095 
1096 	notify_port_select_events(slot, B_EVENT_WRITE);
1097 
1098 	cachedSem = sPorts[slot].write_sem;
1099 
1100 	RELEASE_PORT_LOCK(sPorts[slot]);
1101 	restore_interrupts(state);
1102 
1103 	// check output buffer size
1104 	size = min_c(bufferSize, msg->size);
1105 
1106 	// copy message
1107 	if (_msgCode != NULL)
1108 		*_msgCode = msg->code;
1109 	if (size > 0) {
1110 		if (userCopy) {
1111 			if ((status = cbuf_user_memcpy_from_chain(msgBuffer, msg->buffer_chain, 0, size) < B_OK)) {
1112 				// leave the port intact, for other threads that might not crash
1113 				put_port_msg(msg);
1114 				release_sem(cachedSem);
1115 				return status;
1116 			}
1117 		} else
1118 			cbuf_memcpy_from_chain(msgBuffer, msg->buffer_chain, 0, size);
1119 	}
1120 	put_port_msg(msg);
1121 
1122 	// make one spot in queue available again for write
1123 	release_sem(cachedSem);
1124 		// ToDo: we might think about setting B_NO_RESCHEDULE here
1125 		//	from time to time (always?)
1126 
1127 	return size;
1128 }
1129 
1130 
1131 status_t
1132 write_port(port_id id, int32 msgCode, const void *msgBuffer, size_t bufferSize)
1133 {
1134 	iovec vec = { (void *)msgBuffer, bufferSize };
1135 
1136 	return writev_port_etc(id, msgCode, &vec, 1, bufferSize, 0, 0);
1137 }
1138 
1139 
1140 status_t
1141 write_port_etc(port_id id, int32 msgCode, const void *msgBuffer,
1142 	size_t bufferSize, uint32 flags, bigtime_t timeout)
1143 {
1144 	iovec vec = { (void *)msgBuffer, bufferSize };
1145 
1146 	return writev_port_etc(id, msgCode, &vec, 1, bufferSize, flags, timeout);
1147 }
1148 
1149 
1150 status_t
1151 writev_port_etc(port_id id, int32 msgCode, const iovec *msgVecs,
1152 	size_t vecCount, size_t bufferSize, uint32 flags,
1153 	bigtime_t timeout)
1154 {
1155 	cpu_status state;
1156 	sem_id cachedSem;
1157 	status_t status;
1158 	port_msg *msg;
1159 	bool userCopy = (flags & PORT_FLAG_USE_USER_MEMCPY) > 0;
1160 	int slot;
1161 
1162 	if (!sPortsActive || id < 0)
1163 		return B_BAD_PORT_ID;
1164 
1165 	// mask irrelevant flags (for acquire_sem() usage)
1166 	flags = flags & (B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT
1167 				| B_RELATIVE_TIMEOUT | B_ABSOLUTE_TIMEOUT);
1168 	slot = id % sMaxPorts;
1169 
1170 	if (bufferSize > PORT_MAX_MESSAGE_SIZE)
1171 		return B_BAD_VALUE;
1172 
1173 	state = disable_interrupts();
1174 	GRAB_PORT_LOCK(sPorts[slot]);
1175 
1176 	if (sPorts[slot].id != id) {
1177 		RELEASE_PORT_LOCK(sPorts[slot]);
1178 		restore_interrupts(state);
1179 		TRACE(("write_port_etc: invalid port_id %ld\n", id));
1180 		return B_BAD_PORT_ID;
1181 	}
1182 
1183 	if (is_port_closed(slot)) {
1184 		RELEASE_PORT_LOCK(sPorts[slot]);
1185 		restore_interrupts(state);
1186 		TRACE(("write_port_etc: port %ld closed\n", id));
1187 		return B_BAD_PORT_ID;
1188 	}
1189 
1190 	// store sem_id in local variable
1191 	cachedSem = sPorts[slot].write_sem;
1192 
1193 	RELEASE_PORT_LOCK(sPorts[slot]);
1194 	restore_interrupts(state);
1195 
1196 	status = acquire_sem_etc(cachedSem, 1, flags, timeout);
1197 		// get 1 entry from the queue, block if needed
1198 
1199 	if (status == B_BAD_SEM_ID) {
1200 		// somebody deleted or closed the port
1201 		return B_BAD_PORT_ID;
1202 	}
1203 	if (status != B_OK)
1204 		return status;
1205 
1206 	msg = get_port_msg(msgCode, bufferSize);
1207 	if (msg == NULL)
1208 		return B_NO_MEMORY;
1209 
1210 	// sender credentials
1211 	msg->sender = geteuid();
1212 	msg->sender_group = getegid();
1213 	msg->sender_team = team_get_current_team_id();
1214 
1215 	if (bufferSize > 0) {
1216 		uint32 i;
1217 		if (userCopy) {
1218 			// copy from user memory
1219 			for (i = 0; i < vecCount; i++) {
1220 				size_t bytes = msgVecs[i].iov_len;
1221 				if (bytes > bufferSize)
1222 					bytes = bufferSize;
1223 
1224 				if ((status = cbuf_user_memcpy_to_chain(msg->buffer_chain,
1225 						0, msgVecs[i].iov_base, bytes)) < B_OK) {
1226 					put_port_msg(msg);
1227 					return status;
1228 				}
1229 
1230 				bufferSize -= bytes;
1231 				if (bufferSize == 0)
1232 					break;
1233 			}
1234 		} else {
1235 			// copy from kernel memory
1236 			for (i = 0; i < vecCount; i++) {
1237 				size_t bytes = msgVecs[i].iov_len;
1238 				if (bytes > bufferSize)
1239 					bytes = bufferSize;
1240 
1241 				if ((status = cbuf_memcpy_to_chain(msg->buffer_chain,
1242 						0, msgVecs[i].iov_base, bytes)) < 0) {
1243 					put_port_msg(msg);
1244 					return status;
1245 				}
1246 
1247 				bufferSize -= bytes;
1248 				if (bufferSize == 0)
1249 					break;
1250 			}
1251 		}
1252 	}
1253 
1254 	// attach message to queue
1255 	state = disable_interrupts();
1256 	GRAB_PORT_LOCK(sPorts[slot]);
1257 
1258 	// first, let's check if the port is still alive
1259 	if (sPorts[slot].id == -1) {
1260 		// the port has been deleted in the meantime
1261 		RELEASE_PORT_LOCK(sPorts[slot]);
1262 		restore_interrupts(state);
1263 
1264 		put_port_msg(msg);
1265 		return B_BAD_PORT_ID;
1266 	}
1267 
1268 	list_add_item(&sPorts[slot].msg_queue, msg);
1269 
1270 	notify_port_select_events(slot, B_EVENT_READ);
1271 
1272 	// store sem_id in local variable
1273 	cachedSem = sPorts[slot].read_sem;
1274 
1275 	RELEASE_PORT_LOCK(sPorts[slot]);
1276 	restore_interrupts(state);
1277 
1278 	// release sem, allowing read (might reschedule)
1279 	release_sem(cachedSem);
1280 
1281 	return B_NO_ERROR;
1282 }
1283 
1284 
1285 status_t
1286 set_port_owner(port_id id, team_id team)
1287 {
1288 	cpu_status state;
1289 	int slot;
1290 // ToDo: Shouldn't we at least check, whether the team exists?
1291 
1292 	TRACE(("set_port_owner(id = %ld, team = %ld)\n", id, team));
1293 
1294 	if (!sPortsActive || id < 0)
1295 		return B_BAD_PORT_ID;
1296 
1297 	slot = id % sMaxPorts;
1298 
1299 	state = disable_interrupts();
1300 	GRAB_PORT_LOCK(sPorts[slot]);
1301 
1302 	if (sPorts[slot].id != id) {
1303 		RELEASE_PORT_LOCK(sPorts[slot]);
1304 		restore_interrupts(state);
1305 		TRACE(("set_port_owner: invalid port_id %ld\n", id));
1306 		return B_BAD_PORT_ID;
1307 	}
1308 
1309 	// transfer ownership to other team
1310 	sPorts[slot].owner = team;
1311 
1312 	// unlock port
1313 	RELEASE_PORT_LOCK(sPorts[slot]);
1314 	restore_interrupts(state);
1315 
1316 	return B_NO_ERROR;
1317 }
1318 
1319 
1320 //	#pragma mark - syscalls
1321 
1322 
1323 port_id
1324 _user_create_port(int32 queueLength, const char *userName)
1325 {
1326 	char name[B_OS_NAME_LENGTH];
1327 
1328 	if (userName == NULL)
1329 		return create_port(queueLength, NULL);
1330 
1331 	if (!IS_USER_ADDRESS(userName)
1332 		|| user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK)
1333 		return B_BAD_ADDRESS;
1334 
1335 	return create_port(queueLength, name);
1336 }
1337 
1338 
1339 status_t
1340 _user_close_port(port_id id)
1341 {
1342 	return close_port(id);
1343 }
1344 
1345 
1346 status_t
1347 _user_delete_port(port_id id)
1348 {
1349 	return delete_port(id);
1350 }
1351 
1352 
1353 port_id
1354 _user_find_port(const char *userName)
1355 {
1356 	char name[B_OS_NAME_LENGTH];
1357 
1358 	if (userName == NULL)
1359 		return B_BAD_VALUE;
1360 	if (!IS_USER_ADDRESS(userName)
1361 		|| user_strlcpy(name, userName, B_OS_NAME_LENGTH) < B_OK)
1362 		return B_BAD_ADDRESS;
1363 
1364 	return find_port(name);
1365 }
1366 
1367 
1368 status_t
1369 _user_get_port_info(port_id id, struct port_info *userInfo)
1370 {
1371 	struct port_info info;
1372 	status_t status;
1373 
1374 	if (userInfo == NULL)
1375 		return B_BAD_VALUE;
1376 	if (!IS_USER_ADDRESS(userInfo))
1377 		return B_BAD_ADDRESS;
1378 
1379 	status = get_port_info(id, &info);
1380 
1381 	// copy back to user space
1382 	if (status == B_OK
1383 		&& user_memcpy(userInfo, &info, sizeof(struct port_info)) < B_OK)
1384 		return B_BAD_ADDRESS;
1385 
1386 	return status;
1387 }
1388 
1389 
1390 status_t
1391 _user_get_next_port_info(team_id team, int32 *userCookie,
1392 	struct port_info *userInfo)
1393 {
1394 	struct port_info info;
1395 	status_t status;
1396 	int32 cookie;
1397 
1398 	if (userCookie == NULL || userInfo == NULL)
1399 		return B_BAD_VALUE;
1400 	if (!IS_USER_ADDRESS(userCookie) || !IS_USER_ADDRESS(userInfo)
1401 		|| user_memcpy(&cookie, userCookie, sizeof(int32)) < B_OK)
1402 		return B_BAD_ADDRESS;
1403 
1404 	status = get_next_port_info(team, &cookie, &info);
1405 
1406 	// copy back to user space
1407 	if (user_memcpy(userCookie, &cookie, sizeof(int32)) < B_OK
1408 		|| (status == B_OK && user_memcpy(userInfo, &info,
1409 				sizeof(struct port_info)) < B_OK))
1410 		return B_BAD_ADDRESS;
1411 
1412 	return status;
1413 }
1414 
1415 
1416 ssize_t
1417 _user_port_buffer_size_etc(port_id port, uint32 flags, bigtime_t timeout)
1418 {
1419 	syscall_restart_handle_timeout_pre(flags, timeout);
1420 
1421 	status_t status = port_buffer_size_etc(port, flags | B_CAN_INTERRUPT,
1422 		timeout);
1423 
1424 	return syscall_restart_handle_timeout_post(status, timeout);
1425 }
1426 
1427 
1428 ssize_t
1429 _user_port_count(port_id port)
1430 {
1431 	return port_count(port);
1432 }
1433 
1434 
1435 status_t
1436 _user_set_port_owner(port_id port, team_id team)
1437 {
1438 	return set_port_owner(port, team);
1439 }
1440 
1441 
1442 ssize_t
1443 _user_read_port_etc(port_id port, int32 *userCode, void *userBuffer,
1444 	size_t bufferSize, uint32 flags, bigtime_t timeout)
1445 {
1446 	int32 messageCode;
1447 	ssize_t	bytesRead;
1448 
1449 	syscall_restart_handle_timeout_pre(flags, timeout);
1450 
1451 	if (userBuffer == NULL && bufferSize != 0)
1452 		return B_BAD_VALUE;
1453 	if ((userCode != NULL && !IS_USER_ADDRESS(userCode))
1454 		|| (userBuffer != NULL && !IS_USER_ADDRESS(userBuffer)))
1455 		return B_BAD_ADDRESS;
1456 
1457 	bytesRead = read_port_etc(port, &messageCode, userBuffer, bufferSize,
1458 		flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT, timeout);
1459 
1460 	if (bytesRead >= 0 && userCode != NULL
1461 		&& user_memcpy(userCode, &messageCode, sizeof(int32)) < B_OK)
1462 		return B_BAD_ADDRESS;
1463 
1464 	return syscall_restart_handle_timeout_post(bytesRead, timeout);
1465 }
1466 
1467 
1468 status_t
1469 _user_write_port_etc(port_id port, int32 messageCode, const void *userBuffer,
1470 	size_t bufferSize, uint32 flags, bigtime_t timeout)
1471 {
1472 	iovec vec = { (void *)userBuffer, bufferSize };
1473 
1474 	syscall_restart_handle_timeout_pre(flags, timeout);
1475 
1476 	if (userBuffer == NULL && bufferSize != 0)
1477 		return B_BAD_VALUE;
1478 	if (userBuffer != NULL && !IS_USER_ADDRESS(userBuffer))
1479 		return B_BAD_ADDRESS;
1480 
1481 	status_t status = writev_port_etc(port, messageCode, &vec, 1, bufferSize,
1482 		flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT, timeout);
1483 
1484 	return syscall_restart_handle_timeout_post(status, timeout);
1485 }
1486 
1487 
1488 status_t
1489 _user_writev_port_etc(port_id port, int32 messageCode, const iovec *userVecs,
1490 	size_t vecCount, size_t bufferSize, uint32 flags, bigtime_t timeout)
1491 {
1492 	syscall_restart_handle_timeout_pre(flags, timeout);
1493 
1494 	if (userVecs == NULL && bufferSize != 0)
1495 		return B_BAD_VALUE;
1496 	if (userVecs != NULL && !IS_USER_ADDRESS(userVecs))
1497 		return B_BAD_ADDRESS;
1498 
1499 	iovec *vecs = NULL;
1500 	if (userVecs && vecCount != 0) {
1501 		vecs = (iovec*)malloc(sizeof(iovec) * vecCount);
1502 		if (vecs == NULL)
1503 			return B_NO_MEMORY;
1504 
1505 		if (user_memcpy(vecs, userVecs, sizeof(iovec) * vecCount) < B_OK) {
1506 			free(vecs);
1507 			return B_BAD_ADDRESS;
1508 		}
1509 	}
1510 
1511 	status_t status = writev_port_etc(port, messageCode, vecs, vecCount,
1512 		bufferSize, flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT,
1513 		timeout);
1514 
1515 	free(vecs);
1516 	return syscall_restart_handle_timeout_post(status, timeout);
1517 }
1518 
1519 
1520 status_t
1521 _user_get_port_message_info_etc(port_id port, port_message_info *userInfo,
1522 	size_t infoSize, uint32 flags, bigtime_t timeout)
1523 {
1524 	if (userInfo == NULL || infoSize != sizeof(port_message_info))
1525 		return B_BAD_VALUE;
1526 
1527 	syscall_restart_handle_timeout_pre(flags, timeout);
1528 
1529 	port_message_info info;
1530 	status_t error = _get_port_message_info_etc(port, &info, sizeof(info),
1531 		flags | B_CAN_INTERRUPT, timeout);
1532 
1533 	// copy info to userland
1534 	if (error == B_OK && (!IS_USER_ADDRESS(userInfo)
1535 			|| user_memcpy(userInfo, &info, sizeof(info)) != B_OK)) {
1536 		error = B_BAD_ADDRESS;
1537 	}
1538 
1539 	return syscall_restart_handle_timeout_post(error, timeout);
1540 }
1541