From 31a5ff5d8e1fbeb24ddbfa8591b4133b27cb9d41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Wed, 13 Jul 2005 23:55:15 +0000 Subject: [PATCH] We now have a (private) writev_port_etc() call. This could be used to avoid allocating a buffer and copying your data into it, when you have data to send in several chunks (for example, this could be used by BMessage, as suggested by Ingo Weinhold). Code is untested, but should work. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@13667 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/private/kernel/port.h | 21 +++++--- headers/private/kernel/syscalls.h | 2 + src/system/kernel/port.c | 82 ++++++++++++++++++++++++++++--- 3 files changed, 92 insertions(+), 13 deletions(-) diff --git a/headers/private/kernel/port.h b/headers/private/kernel/port.h index e404f519a4..56ef2ac3a2 100644 --- a/headers/private/kernel/port.h +++ b/headers/private/kernel/port.h @@ -5,7 +5,9 @@ #ifndef _KERNEL_PORT_H #define _KERNEL_PORT_H + #include +#include struct kernel_args; @@ -21,27 +23,34 @@ int delete_owned_ports(team_id owner); int32 port_max_ports(void); int32 port_used_ports(void); +// currently private API +status_t writev_port_etc(port_id id, int32 msgCode, const iovec *msgVecs, + size_t vecCount, size_t bufferSize, uint32 flags, bigtime_t timeout); + // temp: test void port_test(void); // user syscalls -port_id _user_create_port(int32 queue_length, const char *name); +port_id _user_create_port(int32 queueLength, const char *name); status_t _user_close_port(port_id id); status_t _user_delete_port(port_id id); -port_id _user_find_port(const char *port_name); +port_id _user_find_port(const char *portName); status_t _user_get_port_info(port_id id, struct port_info *info); status_t _user_get_next_port_info(team_id team, int32 *cookie, struct port_info *info); ssize_t _user_port_buffer_size_etc(port_id port, uint32 flags, bigtime_t timeout); ssize_t _user_port_count(port_id port); -ssize_t _user_read_port_etc(port_id port, int32 *msg_code, - void *msg_buffer, size_t buffer_size, uint32 flags, +ssize_t _user_read_port_etc(port_id port, int32 *msgCode, + void *msgBuffer, size_t bufferSize, uint32 flags, bigtime_t timeout); status_t _user_set_port_owner(port_id port, team_id team); -status_t _user_write_port_etc(port_id port, int32 msg_code, - const void *msg_buffer, size_t buffer_size, +status_t _user_write_port_etc(port_id port, int32 msgCode, + const void *msgBuffer, size_t bufferSize, uint32 flags, bigtime_t timeout); +status_t _user_writev_port_etc(port_id id, int32 msgCode, + const iovec *msgVecs, size_t vecCount, + size_t bufferSize, uint32 flags, bigtime_t timeout); #ifdef __cplusplus } diff --git a/headers/private/kernel/syscalls.h b/headers/private/kernel/syscalls.h index f2de354b01..39e32864fc 100644 --- a/headers/private/kernel/syscalls.h +++ b/headers/private/kernel/syscalls.h @@ -229,6 +229,8 @@ extern ssize_t _kern_read_port_etc(port_id port, int32 *msgCode, void *msgBuffe extern status_t _kern_set_port_owner(port_id port, team_id team); extern status_t _kern_write_port_etc(port_id port, int32 msgCode, const void *msgBuffer, size_t bufferSize, uint32 flags, bigtime_t timeout); +extern status_t _kern_writev_port_etc(port_id id, int32 msgCode, const iovec *msgVecs, + size_t vecCount, size_t bufferSize, uint32 flags, bigtime_t timeout); // debug support functions extern void _kern_debugger(const char *message); diff --git a/src/system/kernel/port.c b/src/system/kernel/port.c index f4a84d3eda..103805e627 100644 --- a/src/system/kernel/port.c +++ b/src/system/kernel/port.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -964,13 +965,26 @@ read_port_etc(port_id id, int32 *_msgCode, void *msgBuffer, size_t bufferSize, status_t write_port(port_id id, int32 msgCode, const void *msgBuffer, size_t bufferSize) { - return write_port_etc(id, msgCode, msgBuffer, bufferSize, 0, 0); + iovec vec = { (void *)msgBuffer, bufferSize }; + + return writev_port_etc(id, msgCode, &vec, 1, bufferSize, 0, 0); } status_t write_port_etc(port_id id, int32 msgCode, const void *msgBuffer, size_t bufferSize, uint32 flags, bigtime_t timeout) +{ + iovec vec = { (void *)msgBuffer, bufferSize }; + + return writev_port_etc(id, msgCode, &vec, 1, bufferSize, flags, timeout); +} + + +status_t +writev_port_etc(port_id id, int32 msgCode, const iovec *msgVecs, + size_t vecCount, size_t bufferSize, uint32 flags, + bigtime_t timeout) { cpu_status state; sem_id cachedSem; @@ -988,7 +1002,7 @@ write_port_etc(port_id id, int32 msgCode, const void *msgBuffer, slot = id % sMaxPorts; if (bufferSize > PORT_MAX_MESSAGE_SIZE) - return EINVAL; + return B_BAD_VALUE; state = disable_interrupts(); GRAB_PORT_LOCK(sPorts[slot]); @@ -1028,14 +1042,37 @@ write_port_etc(port_id id, int32 msgCode, const void *msgBuffer, return B_NO_MEMORY; if (bufferSize > 0) { + uint32 i; if (userCopy) { // copy from user memory - if ((status = cbuf_user_memcpy_to_chain(msg->buffer_chain, 0, msgBuffer, bufferSize)) < B_OK) - return status; + for (i = 0; i < vecCount; i++) { + size_t bytes = msgVecs[i].iov_len; + if (bytes > bufferSize) + bytes = bufferSize; + + if ((status = cbuf_user_memcpy_to_chain(msg->buffer_chain, + 0, msgVecs[i].iov_base, bytes)) < B_OK) + return status; + + bufferSize -= bytes; + if (bufferSize == 0) + break; + } } else { // copy from kernel memory - if ((status = cbuf_memcpy_to_chain(msg->buffer_chain, 0, msgBuffer, bufferSize)) < 0) - return status; + for (i = 0; i < vecCount; i++) { + size_t bytes = msgVecs[i].iov_len; + if (bytes > bufferSize) + bytes = bufferSize; + + if ((status = cbuf_memcpy_to_chain(msg->buffer_chain, + 0, msgVecs[i].iov_base, bytes)) < 0) + return status; + + bufferSize -= bytes; + if (bufferSize == 0) + break; + } } } @@ -1246,12 +1283,43 @@ status_t _user_write_port_etc(port_id port, int32 messageCode, const void *userBuffer, size_t bufferSize, uint32 flags, bigtime_t timeout) { + iovec vec = { (void *)userBuffer, bufferSize }; + if (userBuffer == NULL && bufferSize != 0) return B_BAD_VALUE; if (userBuffer != NULL && !IS_USER_ADDRESS(userBuffer)) return B_BAD_ADDRESS; - return write_port_etc(port, messageCode, userBuffer, bufferSize, + return writev_port_etc(port, messageCode, &vec, 1, bufferSize, flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT, timeout); } + +status_t +_user_writev_port_etc(port_id port, int32 messageCode, const iovec *userVecs, + size_t vecCount, size_t bufferSize, uint32 flags, bigtime_t timeout) +{ + iovec *vecs = NULL; + status_t status; + + if (userVecs == NULL && bufferSize != 0) + return B_BAD_VALUE; + if (userVecs != NULL && !IS_USER_ADDRESS(userVecs)) + return B_BAD_ADDRESS; + + if (userVecs && vecCount != 0) { + vecs = malloc(sizeof(iovec) * vecCount); + if (vecs == NULL) + return B_NO_MEMORY; + + if (user_memcpy(vecs, userVecs, sizeof(iovec) * vecCount) < B_OK) { + free(vecs); + return B_BAD_ADDRESS; + } + } + status = writev_port_etc(port, messageCode, vecs, vecCount, bufferSize, + flags | PORT_FLAG_USE_USER_MEMCPY | B_CAN_INTERRUPT, timeout); + + free(vecs); + return status; +}