2 ** Copyright 2001-2004, Mark-Jan Bastian. All rights reserved.
3 ** Distributed under the terms of the NewOS License.
6 #include <kernel/kernel.h>
7 #include <kernel/port.h>
8 #include <kernel/sem.h>
9 #include <kernel/int.h>
10 #include <kernel/debug.h>
11 #include <kernel/heap.h>
12 #include <kernel/vm.h>
13 #include <kernel/cbuf.h>
14 #include <newos/errors.h>
37 struct port_msg
* msg_queue
;
41 void dump_port_list(int argc
, char **argv
);
42 static void _dump_port_info(struct port_entry
*port
);
43 static void dump_port_info(int argc
, char **argv
);
46 // MAX_PORTS must be power of 2
47 #define MAX_PORTS 4096
48 #define MAX_QUEUE_LENGTH 4096
49 #define PORT_MAX_MESSAGE_SIZE 65536
51 static struct port_entry
*ports
= NULL
;
52 static region_id port_region
= 0;
53 static bool ports_active
= false;
55 static port_id next_port
= 0;
57 static int port_spinlock
= 0;
58 #define GRAB_PORT_LIST_LOCK() acquire_spinlock(&port_spinlock)
59 #define RELEASE_PORT_LIST_LOCK() release_spinlock(&port_spinlock)
60 #define GRAB_PORT_LOCK(s) acquire_spinlock(&(s).lock)
61 #define RELEASE_PORT_LOCK(s) release_spinlock(&(s).lock)
63 int port_init(kernel_args
*ka
)
68 sz
= sizeof(struct port_entry
) * MAX_PORTS
;
70 // create and initialize semaphore table
71 port_region
= vm_create_anonymous_region(vm_get_kernel_aspace_id(), "port_table", (void **)&ports
,
72 REGION_ADDR_ANY_ADDRESS
, sz
, REGION_WIRING_WIRED
, LOCK_RW
|LOCK_KERNEL
);
74 panic("unable to allocate kernel port table!\n");
78 for(i
=0; i
<MAX_PORTS
; i
++)
81 // add debugger commands
82 dbg_add_command(&dump_port_list
, "ports", "Dump a list of all active ports");
83 dbg_add_command(&dump_port_info
, "port", "Dump info about a particular port");
90 void dump_port_list(int argc
, char **argv
)
94 for(i
=0; i
<MAX_PORTS
; i
++) {
95 if(ports
[i
].id
>= 0) {
96 dprintf("%p\tid: 0x%x\t\tname: '%s'\n", &ports
[i
], ports
[i
].id
, ports
[i
].name
);
101 static void _dump_port_info(struct port_entry
*port
)
104 dprintf("PORT: %p\n", port
);
105 dprintf("name: '%s'\n", port
->name
);
106 dprintf("owner: 0x%x\n", port
->owner
);
107 dprintf("cap: %d\n", port
->capacity
);
108 dprintf("head: %d\n", port
->head
);
109 dprintf("tail: %d\n", port
->tail
);
110 sem_get_count(port
->read_sem
, &cnt
);
111 dprintf("read_sem: %d\n", cnt
);
112 sem_get_count(port
->read_sem
, &cnt
);
113 dprintf("write_sem: %d\n", cnt
);
116 static void dump_port_info(int argc
, char **argv
)
121 dprintf("port: not enough arguments\n");
125 // if the argument looks like a hex number, treat it as such
126 if(strlen(argv
[1]) > 2 && argv
[1][0] == '0' && argv
[1][1] == 'x') {
127 unsigned long num
= atoul(argv
[1]);
129 if(is_kernel_address(num
)) {
131 // one can use either address or a port_id, since KERNEL_BASE > MAX_PORTS assumed
132 _dump_port_info((struct port_entry
*)num
);
135 unsigned slot
= num
% MAX_PORTS
;
136 if(ports
[slot
].id
!= (int)num
) {
137 dprintf("port 0x%lx doesn't exist!\n", num
);
140 _dump_port_info(&ports
[slot
]);
145 // walk through the ports list, trying to match name
146 for(i
=0; i
<MAX_PORTS
; i
++) {
147 if (ports
[i
].name
!= NULL
)
148 if(strcmp(argv
[1], ports
[i
].name
) == 0) {
149 _dump_port_info(&ports
[i
]);
156 port_create(int32 queue_length
, const char *name
)
166 if(ports_active
== false)
167 return ERR_PORT_NOT_ACTIVE
;
170 name
= "unnamed port";
172 name_len
= strlen(name
) + 1;
173 name_len
= min(name_len
, SYS_MAX_OS_NAME_LEN
);
175 temp_name
= (char *)kmalloc(name_len
);
176 if(temp_name
== NULL
)
177 return ERR_NO_MEMORY
;
179 strlcpy(temp_name
, name
, name_len
);
181 // check queue length
182 if (queue_length
< 1 || queue_length
> MAX_QUEUE_LENGTH
) {
184 return ERR_INVALID_ARGS
;
188 q
= kmalloc( queue_length
* sizeof(struct port_msg
) );
190 kfree(temp_name
); // dealloc name, too
191 return ERR_NO_MEMORY
;
194 // create sem_r with owner set to -1
195 sem_r
= sem_create_etc(0, temp_name
, -1);
204 sem_w
= sem_create_etc(queue_length
, temp_name
, -1);
212 owner
= proc_get_current_proc_id();
214 int_disable_interrupts();
215 GRAB_PORT_LIST_LOCK();
217 // find the first empty spot
218 for(i
=0; i
<MAX_PORTS
; i
++) {
219 if(ports
[i
].id
== -1) {
220 // make the port_id be a multiple of the slot it's in
221 if(i
>= next_port
% MAX_PORTS
) {
222 next_port
+= i
- next_port
% MAX_PORTS
;
224 next_port
+= MAX_PORTS
- (next_port
% MAX_PORTS
- i
);
226 ports
[i
].id
= next_port
++;
228 GRAB_PORT_LOCK(ports
[i
]);
229 RELEASE_PORT_LIST_LOCK();
231 ports
[i
].capacity
= queue_length
;
232 ports
[i
].name
= temp_name
;
235 ports
[i
].read_sem
= sem_r
;
236 ports
[i
].write_sem
= sem_w
;
237 ports
[i
].msg_queue
= q
;
240 ports
[i
].total_count
= 0;
241 ports
[i
].owner
= owner
;
242 retval
= ports
[i
].id
;
243 RELEASE_PORT_LOCK(ports
[i
]);
247 // not enough ports...
248 RELEASE_PORT_LIST_LOCK();
251 retval
= ERR_PORT_OUT_OF_SLOTS
;
252 dprintf("port_create(): ERR_PORT_OUT_OF_SLOTS\n");
261 int_restore_interrupts();
267 port_close(port_id id
)
271 if(ports_active
== false)
272 return ERR_PORT_NOT_ACTIVE
;
274 return ERR_INVALID_HANDLE
;
275 slot
= id
% MAX_PORTS
;
277 // walk through the sem list, trying to match name
278 int_disable_interrupts();
279 GRAB_PORT_LOCK(ports
[slot
]);
281 if (ports
[slot
].id
!= id
) {
282 RELEASE_PORT_LOCK(ports
[slot
]);
283 int_restore_interrupts();
284 return ERR_INVALID_HANDLE
;
287 // mark port to disable writing
288 ports
[slot
].closed
= true;
290 RELEASE_PORT_LOCK(ports
[slot
]);
291 int_restore_interrupts();
297 port_delete(port_id id
)
307 if(ports_active
== false)
308 return ERR_PORT_NOT_ACTIVE
;
310 return ERR_INVALID_HANDLE
;
312 slot
= id
% MAX_PORTS
;
314 int_disable_interrupts();
315 GRAB_PORT_LOCK(ports
[slot
]);
317 if(ports
[slot
].id
!= id
) {
318 RELEASE_PORT_LOCK(ports
[slot
]);
319 int_restore_interrupts();
320 dprintf("port_delete: invalid port_id %d\n", id
);
321 return ERR_INVALID_HANDLE
;
324 /* mark port as invalid */
326 old_name
= ports
[slot
].name
;
327 q
= ports
[slot
].msg_queue
;
328 r_sem
= ports
[slot
].read_sem
;
329 w_sem
= ports
[slot
].write_sem
;
330 capacity
= ports
[slot
].capacity
;
331 ports
[slot
].name
= NULL
;
333 RELEASE_PORT_LOCK(ports
[slot
]);
334 int_restore_interrupts();
336 // delete the cbuf's that are left in the queue (if any)
337 for (i
=0; i
<capacity
; i
++) {
338 if (q
[i
].data_cbuf
!= NULL
)
339 cbuf_free_chain(q
[i
].data_cbuf
);
345 // release the threads that were blocking on this port by deleting the sem
346 // read_port() will see the ERR_SEM_DELETED acq_sem() return value, and act accordingly
354 port_find(const char *port_name
)
357 int ret_val
= ERR_INVALID_HANDLE
;
359 if(ports_active
== false)
360 return ERR_PORT_NOT_ACTIVE
;
361 if(port_name
== NULL
)
362 return ERR_INVALID_HANDLE
;
364 // lock list of ports
365 int_disable_interrupts();
366 GRAB_PORT_LIST_LOCK();
369 for(i
=0; i
<MAX_PORTS
; i
++) {
370 // lock every individual port before comparing
371 GRAB_PORT_LOCK(ports
[i
]);
372 if(ports
[i
].id
>= 0 && strcmp(port_name
, ports
[i
].name
) == 0) {
373 ret_val
= ports
[i
].id
;
374 RELEASE_PORT_LOCK(ports
[i
]);
377 RELEASE_PORT_LOCK(ports
[i
]);
380 RELEASE_PORT_LIST_LOCK();
381 int_restore_interrupts();
387 port_get_info(port_id id
, struct port_info
*info
)
391 if(ports_active
== false)
392 return ERR_PORT_NOT_ACTIVE
;
394 return ERR_INVALID_ARGS
;
396 return ERR_INVALID_HANDLE
;
398 slot
= id
% MAX_PORTS
;
400 int_disable_interrupts();
401 GRAB_PORT_LOCK(ports
[slot
]);
403 if(ports
[slot
].id
!= id
) {
404 RELEASE_PORT_LOCK(ports
[slot
]);
405 int_restore_interrupts();
406 dprintf("port_get_info: invalid port_id %d\n", id
);
407 return ERR_INVALID_HANDLE
;
410 // fill a port_info struct with info
411 info
->id
= ports
[slot
].id
;
412 info
->owner
= ports
[slot
].owner
;
413 strncpy(info
->name
, ports
[slot
].name
, min(strlen(ports
[slot
].name
),SYS_MAX_OS_NAME_LEN
-1));
414 info
->capacity
= ports
[slot
].capacity
;
415 sem_get_count(ports
[slot
].read_sem
, &info
->queue_count
);
416 info
->total_count
= ports
[slot
].total_count
;
418 RELEASE_PORT_LOCK(ports
[slot
]);
419 int_restore_interrupts();
421 // from our port_entry
426 port_get_next_port_info(proc_id proc
,
428 struct port_info
*info
)
432 if(ports_active
== false)
433 return ERR_PORT_NOT_ACTIVE
;
435 return ERR_INVALID_ARGS
;
437 if (*cookie
== NULL
) {
438 // return first found
441 // start at index cookie, but check cookie against MAX_PORTS
443 if (slot
>= MAX_PORTS
)
444 return ERR_INVALID_HANDLE
;
448 int_disable_interrupts();
449 GRAB_PORT_LIST_LOCK();
451 info
->id
= -1; // used as found flag
452 while (slot
< MAX_PORTS
) {
453 GRAB_PORT_LOCK(ports
[slot
]);
454 if (ports
[slot
].id
!= -1)
455 if (ports
[slot
].owner
== proc
) {
458 info
->id
= ports
[slot
].id
;
459 info
->owner
= ports
[slot
].owner
;
460 strncpy(info
->name
, ports
[slot
].name
, min(strlen(ports
[slot
].name
),SYS_MAX_OS_NAME_LEN
-1));
461 info
->capacity
= ports
[slot
].capacity
;
462 sem_get_count(ports
[slot
].read_sem
, &info
->queue_count
);
463 info
->total_count
= ports
[slot
].total_count
;
464 RELEASE_PORT_LOCK(ports
[slot
]);
468 RELEASE_PORT_LOCK(ports
[slot
]);
471 RELEASE_PORT_LIST_LOCK();
472 int_restore_interrupts();
475 return ERR_PORT_NOT_FOUND
;
481 port_buffer_size(port_id id
)
483 return port_buffer_size_etc(id
, 0, 0);
487 port_buffer_size_etc(port_id id
,
496 if(ports_active
== false)
497 return ERR_PORT_NOT_ACTIVE
;
499 return ERR_INVALID_HANDLE
;
501 slot
= id
% MAX_PORTS
;
503 int_disable_interrupts();
504 GRAB_PORT_LOCK(ports
[slot
]);
506 if(ports
[slot
].id
!= id
) {
507 RELEASE_PORT_LOCK(ports
[slot
]);
508 int_restore_interrupts();
509 dprintf("port_get_info: invalid port_id %d\n", id
);
510 return ERR_INVALID_HANDLE
;
512 RELEASE_PORT_LOCK(ports
[slot
]);
513 int_restore_interrupts();
515 // block if no message,
516 // if TIMEOUT flag set, block with timeout
518 // XXX - is it a race condition to acquire a sem just after we
519 // unlocked the port ?
520 // XXX: call an acquire_sem which does the release lock, restore int & block the right way
521 res
= sem_acquire_etc(ports
[slot
].read_sem
, 1, flags
& (SEM_FLAG_TIMEOUT
| SEM_FLAG_INTERRUPTABLE
), timeout
, NULL
);
523 GRAB_PORT_LOCK(ports
[slot
]);
524 if (res
== ERR_SEM_DELETED
) {
525 // somebody deleted the port
526 RELEASE_PORT_LOCK(ports
[slot
]);
527 return ERR_PORT_DELETED
;
529 if (res
== ERR_SEM_TIMED_OUT
) {
530 RELEASE_PORT_LOCK(ports
[slot
]);
531 return ERR_PORT_TIMED_OUT
;
534 // once message arrived, read data's length
537 // read data's head length
538 t
= ports
[slot
].head
;
540 panic("port %id: tail < 0", ports
[slot
].id
);
541 if (t
> ports
[slot
].capacity
)
542 panic("port %id: tail > cap %d", ports
[slot
].id
, ports
[slot
].capacity
);
543 len
= ports
[slot
].msg_queue
[t
].data_len
;
546 sem_release(ports
[slot
].read_sem
, 1);
548 RELEASE_PORT_LOCK(ports
[slot
]);
550 // return length of item at end of queue
555 port_count(port_id id
)
560 if(ports_active
== false)
561 return ERR_PORT_NOT_ACTIVE
;
563 return ERR_INVALID_HANDLE
;
565 slot
= id
% MAX_PORTS
;
567 int_disable_interrupts();
568 GRAB_PORT_LOCK(ports
[slot
]);
570 if(ports
[slot
].id
!= id
) {
571 RELEASE_PORT_LOCK(ports
[slot
]);
572 int_restore_interrupts();
573 dprintf("port_count: invalid port_id %d\n", id
);
574 return ERR_INVALID_HANDLE
;
577 sem_get_count(ports
[slot
].read_sem
, &count
);
578 // do not return negative numbers
582 RELEASE_PORT_LOCK(ports
[slot
]);
583 int_restore_interrupts();
585 // return count of messages (sem_count)
590 port_read(port_id port
,
595 return port_read_etc(port
, msg_code
, msg_buffer
, buffer_size
, 0, 0);
599 port_read_etc(port_id id
,
615 if(ports_active
== false)
616 return ERR_PORT_NOT_ACTIVE
;
618 return ERR_INVALID_HANDLE
;
620 return ERR_INVALID_ARGS
;
621 if((msg_buffer
== NULL
) && (buffer_size
> 0))
622 return ERR_INVALID_ARGS
;
624 return ERR_INVALID_ARGS
;
626 flags
= flags
& (PORT_FLAG_USE_USER_MEMCPY
| PORT_FLAG_INTERRUPTABLE
| PORT_FLAG_TIMEOUT
);
628 slot
= id
% MAX_PORTS
;
630 int_disable_interrupts();
631 GRAB_PORT_LOCK(ports
[slot
]);
633 if(ports
[slot
].id
!= id
) {
634 RELEASE_PORT_LOCK(ports
[slot
]);
635 int_restore_interrupts();
636 dprintf("read_port_etc: invalid port_id %d\n", id
);
637 return ERR_INVALID_HANDLE
;
639 // store sem_id in local variable
640 cached_semid
= ports
[slot
].read_sem
;
642 // unlock port && enable ints/
643 RELEASE_PORT_LOCK(ports
[slot
]);
644 int_restore_interrupts();
646 // XXX -> possible race condition if port gets deleted (->sem deleted too), therefore
647 // sem_id is cached in local variable up here
649 // get 1 entry from the queue, block if needed
650 res
= sem_acquire_etc(cached_semid
, 1,
651 flags
, timeout
, NULL
);
653 // XXX: possible race condition if port read by two threads...
654 // both threads will read in 2 different slots allocated above, simultaneously
655 // slot is a thread-local variable
657 if (res
== ERR_SEM_DELETED
) {
658 // somebody deleted the port
659 return ERR_PORT_DELETED
;
662 if (res
== ERR_SEM_INTERRUPTED
) {
663 // XXX: somebody signaled the process the port belonged to, deleting the sem ?
664 return ERR_PORT_INTERRUPTED
;
667 if (res
== ERR_SEM_TIMED_OUT
) {
668 // timed out, or, if timeout=0, 'would block'
669 return ERR_PORT_TIMED_OUT
;
672 if (res
!= NO_ERROR
) {
673 dprintf("write_port_etc: res unknown error %d\n", res
);
677 int_disable_interrupts();
678 GRAB_PORT_LOCK(ports
[slot
]);
680 t
= ports
[slot
].tail
;
682 panic("port %id: tail < 0", ports
[slot
].id
);
683 if (t
> ports
[slot
].capacity
)
684 panic("port %id: tail > cap %d", ports
[slot
].id
, ports
[slot
].capacity
);
686 ports
[slot
].tail
= (ports
[slot
].tail
+ 1) % ports
[slot
].capacity
;
688 msg_store
= ports
[slot
].msg_queue
[t
].data_cbuf
;
689 code
= ports
[slot
].msg_queue
[t
].msg_code
;
691 // mark queue entry unused
692 ports
[slot
].msg_queue
[t
].data_cbuf
= NULL
;
694 // check output buffer size
695 siz
= min(buffer_size
, ports
[slot
].msg_queue
[t
].data_len
);
697 cached_semid
= ports
[slot
].write_sem
;
699 RELEASE_PORT_LOCK(ports
[slot
]);
700 int_restore_interrupts();
705 if (flags
& PORT_FLAG_USE_USER_MEMCPY
) {
706 if ((err
= cbuf_user_memcpy_from_chain(msg_buffer
, msg_store
, 0, siz
) < 0)) {
707 // leave the port intact, for other threads that might not crash
708 cbuf_free_chain(msg_store
);
709 sem_release(cached_semid
, 1);
713 cbuf_memcpy_from_chain(msg_buffer
, msg_store
, 0, siz
);
716 cbuf_free_chain(msg_store
);
718 // make one spot in queue available again for write
719 sem_release(cached_semid
, 1);
725 port_set_owner(port_id id
, proc_id proc
)
729 if(ports_active
== false)
730 return ERR_PORT_NOT_ACTIVE
;
732 return ERR_INVALID_HANDLE
;
734 slot
= id
% MAX_PORTS
;
736 int_disable_interrupts();
737 GRAB_PORT_LOCK(ports
[slot
]);
739 if(ports
[slot
].id
!= id
) {
740 RELEASE_PORT_LOCK(ports
[slot
]);
741 int_restore_interrupts();
742 dprintf("port_set_owner: invalid port_id %d\n", id
);
743 return ERR_INVALID_HANDLE
;
746 // transfer ownership to other process
747 ports
[slot
].owner
= proc
;
750 RELEASE_PORT_LOCK(ports
[slot
]);
751 int_restore_interrupts();
757 port_write(port_id id
,
762 return port_write_etc(id
, msg_code
, msg_buffer
, buffer_size
, 0, 0);
766 port_write_etc(port_id id
,
781 if(ports_active
== false)
782 return ERR_PORT_NOT_ACTIVE
;
784 return ERR_INVALID_HANDLE
;
786 // mask irrelevant flags
787 flags
= flags
& (PORT_FLAG_USE_USER_MEMCPY
| PORT_FLAG_INTERRUPTABLE
| PORT_FLAG_TIMEOUT
);
789 slot
= id
% MAX_PORTS
;
792 if (buffer_size
> PORT_MAX_MESSAGE_SIZE
)
793 return ERR_INVALID_ARGS
;
795 int_disable_interrupts();
796 GRAB_PORT_LOCK(ports
[slot
]);
798 if(ports
[slot
].id
!= id
) {
799 RELEASE_PORT_LOCK(ports
[slot
]);
800 int_restore_interrupts();
801 dprintf("write_port_etc: invalid port_id %d\n", id
);
802 return ERR_INVALID_HANDLE
;
805 if (ports
[slot
].closed
) {
806 RELEASE_PORT_LOCK(ports
[slot
]);
807 int_restore_interrupts();
808 dprintf("write_port_etc: port %d closed\n", id
);
809 return ERR_PORT_CLOSED
;
812 // store sem_id in local variable
813 cached_semid
= ports
[slot
].write_sem
;
815 RELEASE_PORT_LOCK(ports
[slot
]);
816 int_restore_interrupts();
818 // XXX -> possible race condition if port gets deleted (->sem deleted too),
819 // and queue is full therefore sem_id is cached in local variable up here
821 // get 1 entry from the queue, block if needed
823 res
= sem_acquire_etc(cached_semid
, 1,
824 flags
& (SEM_FLAG_TIMEOUT
| SEM_FLAG_INTERRUPTABLE
), timeout
, NULL
);
826 // XXX: possible race condition if port written by two threads...
827 // both threads will write in 2 different slots allocated above, simultaneously
828 // slot is a thread-local variable
830 if (res
== ERR_SEM_DELETED
) {
831 // somebody deleted the port
832 return ERR_PORT_DELETED
;
835 if (res
== ERR_SEM_INTERRUPTED
) {
836 // XXX: somebody signaled the process the port belonged to, deleting the sem ?
837 return ERR_PORT_INTERRUPTED
;
840 if (res
== ERR_SEM_TIMED_OUT
) {
841 // timed out, or, if timeout=0, 'would block'
842 return ERR_PORT_TIMED_OUT
;
845 if (res
!= NO_ERROR
) {
846 dprintf("write_port_etc: res unknown error %d\n", res
);
850 if (buffer_size
> 0) {
851 msg_store
= cbuf_get_chain(buffer_size
);
852 if (msg_store
== NULL
)
853 return ERR_NO_MEMORY
;
854 if (flags
& PORT_FLAG_USE_USER_MEMCPY
) {
855 // copy from user memory
856 if ((err
= cbuf_user_memcpy_to_chain(msg_store
, 0, msg_buffer
, buffer_size
)) < 0)
857 return err
; // memory exception
859 // copy from kernel memory
860 if ((err
= cbuf_memcpy_to_chain(msg_store
, 0, msg_buffer
, buffer_size
)) < 0)
861 return err
; // memory exception
866 // attach copied message to queue
867 int_disable_interrupts();
868 GRAB_PORT_LOCK(ports
[slot
]);
870 h
= ports
[slot
].head
;
872 panic("port %id: head < 0", ports
[slot
].id
);
873 if (h
>= ports
[slot
].capacity
)
874 panic("port %id: head > cap %d", ports
[slot
].id
, ports
[slot
].capacity
);
875 ports
[slot
].msg_queue
[h
].msg_code
= msg_code
;
876 ports
[slot
].msg_queue
[h
].data_cbuf
= msg_store
;
877 ports
[slot
].msg_queue
[h
].data_len
= buffer_size
;
878 ports
[slot
].head
= (ports
[slot
].head
+ 1) % ports
[slot
].capacity
;
879 ports
[slot
].total_count
++;
881 // store sem_id in local variable
882 cached_semid
= ports
[slot
].read_sem
;
884 RELEASE_PORT_LOCK(ports
[slot
]);
885 int_restore_interrupts();
887 sem_get_count(ports
[slot
].read_sem
, &c1
);
888 sem_get_count(ports
[slot
].write_sem
, &c2
);
890 // release sem, allowing read (might reschedule)
891 sem_release(cached_semid
, 1);
896 /* this function cycles through the ports table, deleting all the ports that are owned by
897 the passed proc_id */
898 int port_delete_owned_ports(proc_id owner
)
903 if(ports_active
== false)
904 return ERR_PORT_NOT_ACTIVE
;
906 int_disable_interrupts();
907 GRAB_PORT_LIST_LOCK();
909 for(i
=0; i
<MAX_PORTS
; i
++) {
910 if(ports
[i
].id
!= -1 && ports
[i
].owner
== owner
) {
911 port_id id
= ports
[i
].id
;
913 RELEASE_PORT_LIST_LOCK();
914 int_restore_interrupts();
919 int_disable_interrupts();
920 GRAB_PORT_LIST_LOCK();
924 RELEASE_PORT_LIST_LOCK();
925 int_restore_interrupts();
935 port_id test_p1
, test_p2
, test_p3
, test_p4
;
945 strcpy(testdata
, "abcd");
947 dprintf("porttest: port_create()\n");
948 test_p1
= port_create(1, "test port #1");
949 test_p2
= port_create(10, "test port #2");
950 test_p3
= port_create(1024, "test port #3");
951 test_p4
= port_create(1024, "test port #4");
953 dprintf("porttest: port_find()\n");
954 dprintf("'test port #1' has id %d (should be %d)\n", port_find("test port #1"), test_p1
);
956 dprintf("porttest: port_write() on 1, 2 and 3\n");
957 port_write(test_p1
, 1, &testdata
, sizeof(testdata
));
958 port_write(test_p2
, 666, &testdata
, sizeof(testdata
));
959 port_write(test_p3
, 999, &testdata
, sizeof(testdata
));
960 dprintf("porttest: port_count(test_p1) = %d\n", port_count(test_p1
));
962 dprintf("porttest: port_write() on 1 with timeout of 1 sec (blocks 1 sec)\n");
963 port_write_etc(test_p1
, 1, &testdata
, sizeof(testdata
), PORT_FLAG_TIMEOUT
, 1000000);
964 dprintf("porttest: port_write() on 2 with timeout of 1 sec (wont block)\n");
965 res
= port_write_etc(test_p2
, 777, &testdata
, sizeof(testdata
), PORT_FLAG_TIMEOUT
, 1000000);
966 dprintf("porttest: res=%d, %s\n", res
, res
== 0 ? "ok" : "BAD");
968 dprintf("porttest: port_read() on empty port 4 with timeout of 1 sec (blocks 1 sec)\n");
969 res
= port_read_etc(test_p4
, &dummy
, &dummy2
, sizeof(dummy2
), PORT_FLAG_TIMEOUT
, 1000000);
970 dprintf("porttest: res=%d, %s\n", res
, res
== ERR_PORT_TIMED_OUT
? "ok" : "BAD");
972 dprintf("porttest: spawning thread for port 1\n");
973 t
= thread_create_kernel_thread("port_test", port_test_thread_func
, NULL
);
975 thread_resume_thread(t
);
977 dprintf("porttest: write\n");
978 port_write(test_p1
, 1, &testdata
, sizeof(testdata
));
980 // now we can write more (no blocking)
981 dprintf("porttest: write #2\n");
982 port_write(test_p1
, 2, &testdata
, sizeof(testdata
));
983 dprintf("porttest: write #3\n");
984 port_write(test_p1
, 3, &testdata
, sizeof(testdata
));
986 dprintf("porttest: waiting on spawned thread\n");
987 thread_wait_on_thread(t
, NULL
);
989 dprintf("porttest: close p1\n");
991 dprintf("porttest: attempt write p1 after close\n");
992 res
= port_write(test_p2
, 4, &testdata
, sizeof(testdata
));
993 dprintf("porttest: port_write ret %d\n", res
);
995 dprintf("porttest: testing delete p2\n");
996 port_delete(test_p2
);
998 dprintf("porttest: end test main thread\n");
1002 int port_test_thread_func(void* arg
)
1009 dprintf("porttest: port_test_thread_func()\n");
1011 n
= port_read(test_p1
, &msg_code
, &buf
, 3);
1012 dprintf("port_read #1 code %d len %d buf %s\n", msg_code
, n
, buf
);
1013 n
= port_read(test_p1
, &msg_code
, &buf
, 4);
1014 dprintf("port_read #1 code %d len %d buf %s\n", msg_code
, n
, buf
);
1016 n
= port_read(test_p1
, &msg_code
, &buf
, 5);
1017 dprintf("port_read #1 code %d len %d buf %s\n", msg_code
, n
, buf
);
1019 dprintf("porttest: testing delete p1 from other thread\n");
1020 port_delete(test_p1
);
1021 dprintf("porttest: end port_test_thread_func()\n");
1030 port_id
user_port_create(int32 queue_length
, const char *uname
)
1032 dprintf("user_port_create: queue_length %d\n", queue_length
);
1034 char name
[SYS_MAX_OS_NAME_LEN
];
1037 if(is_kernel_address(uname
))
1038 return ERR_VM_BAD_USER_MEMORY
;
1040 rc
= user_strncpy(name
, uname
, SYS_MAX_OS_NAME_LEN
-1);
1043 name
[SYS_MAX_OS_NAME_LEN
-1] = 0;
1045 return port_create(queue_length
, name
);
1047 return port_create(queue_length
, NULL
);
1051 int user_port_close(port_id id
)
1053 return port_close(id
);
1056 int user_port_delete(port_id id
)
1058 return port_delete(id
);
1061 port_id
user_port_find(const char *port_name
)
1063 if(port_name
!= NULL
) {
1064 char name
[SYS_MAX_OS_NAME_LEN
];
1067 if(is_kernel_address(port_name
))
1068 return ERR_VM_BAD_USER_MEMORY
;
1070 rc
= user_strncpy(name
, port_name
, SYS_MAX_OS_NAME_LEN
-1);
1073 name
[SYS_MAX_OS_NAME_LEN
-1] = 0;
1075 return port_find(name
);
1077 return ERR_INVALID_ARGS
;
1081 int user_port_get_info(port_id id
, struct port_info
*uinfo
)
1084 struct port_info info
;
1088 return ERR_INVALID_ARGS
;
1089 if(is_kernel_address(uinfo
))
1090 return ERR_VM_BAD_USER_MEMORY
;
1092 res
= port_get_info(id
, &info
);
1093 // copy to userspace
1094 rc
= user_memcpy(uinfo
, &info
, sizeof(struct port_info
));
1100 int user_port_get_next_port_info(proc_id uproc
,
1102 struct port_info
*uinfo
)
1105 struct port_info info
;
1109 if (ucookie
== NULL
)
1110 return ERR_INVALID_ARGS
;
1112 return ERR_INVALID_ARGS
;
1113 if(is_kernel_address(ucookie
))
1114 return ERR_VM_BAD_USER_MEMORY
;
1115 if(is_kernel_address(uinfo
))
1116 return ERR_VM_BAD_USER_MEMORY
;
1118 // copy from userspace
1119 rc
= user_memcpy(&cookie
, ucookie
, sizeof(uint32
));
1123 res
= port_get_next_port_info(uproc
, &cookie
, &info
);
1124 // copy to userspace
1125 rc
= user_memcpy(ucookie
, &info
, sizeof(uint32
));
1128 rc
= user_memcpy(uinfo
, &info
, sizeof(struct port_info
));
1134 ssize_t
user_port_buffer_size(port_id port
)
1136 return port_buffer_size_etc(port
, SEM_FLAG_INTERRUPTABLE
, 0);
1139 ssize_t
user_port_buffer_size_etc(port_id port
, uint32 flags
, bigtime_t timeout
)
1141 return port_buffer_size_etc(port
, flags
| SEM_FLAG_INTERRUPTABLE
, timeout
);
1144 int32
user_port_count(port_id port
)
1146 return port_count(port
);
1149 ssize_t
user_port_read(port_id uport
, int32
*umsg_code
, void *umsg_buffer
,
1150 size_t ubuffer_size
)
1152 return user_port_read_etc(uport
, umsg_code
, umsg_buffer
, ubuffer_size
, 0, 0);
1155 ssize_t
user_port_read_etc(port_id uport
, int32
*umsg_code
, void *umsg_buffer
,
1156 size_t ubuffer_size
, uint32 uflags
, bigtime_t utimeout
)
1162 if (umsg_code
== NULL
)
1163 return ERR_INVALID_ARGS
;
1164 if (umsg_buffer
== NULL
)
1165 return ERR_INVALID_ARGS
;
1167 if(is_kernel_address(umsg_code
))
1168 return ERR_VM_BAD_USER_MEMORY
;
1169 if(is_kernel_address(umsg_buffer
))
1170 return ERR_VM_BAD_USER_MEMORY
;
1172 res
= port_read_etc(uport
, &msg_code
, umsg_buffer
, ubuffer_size
,
1173 uflags
| PORT_FLAG_USE_USER_MEMCPY
| SEM_FLAG_INTERRUPTABLE
, utimeout
);
1175 rc
= user_memcpy(umsg_code
, &msg_code
, sizeof(int32
));
1182 int user_port_set_owner(port_id port
, proc_id proc
)
1184 return port_set_owner(port
, proc
);
1187 int user_port_write(port_id uport
, int32 umsg_code
, void *umsg_buffer
,
1188 size_t ubuffer_size
)
1190 return user_port_write_etc(uport
, umsg_code
, umsg_buffer
, ubuffer_size
, 0, 0);
1193 int user_port_write_etc(port_id uport
, int32 umsg_code
, void *umsg_buffer
,
1194 size_t ubuffer_size
, uint32 uflags
, bigtime_t utimeout
)
1196 if (umsg_buffer
== NULL
)
1197 return ERR_INVALID_ARGS
;
1198 if(is_kernel_address(umsg_buffer
))
1199 return ERR_VM_BAD_USER_MEMORY
;
1200 return port_write_etc(uport
, umsg_code
, umsg_buffer
, ubuffer_size
,
1201 uflags
| PORT_FLAG_USE_USER_MEMCPY
| SEM_FLAG_INTERRUPTABLE
, utimeout
);