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