mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-11-01 15:08:21 +00:00
udp: prepare for copyless read/write
This commit is contained in:
+27
-25
@@ -45,11 +45,15 @@ int udp_sendpacket(void *buffer, size_t size, uint32_t ip, uint16_t srcport, uin
|
|||||||
};
|
};
|
||||||
|
|
||||||
memcpy(newbuff, &frame, sizeof(udpframe_t));
|
memcpy(newbuff, &frame, sizeof(udpframe_t));
|
||||||
memcpy((void *)((uintptr_t)newbuff + sizeof(udpframe_t)), buffer, size);
|
int error = USERCOPY_POSSIBLY_FROM_USER((void *)((uintptr_t)newbuff + sizeof(udpframe_t)), buffer, size);
|
||||||
|
if (error)
|
||||||
|
goto leave;
|
||||||
|
|
||||||
int e = ipv4_sendpacket(newbuff, size + sizeof(udpframe_t), ip, IPV4_PROTO_UDP, broadcastnetdev);
|
error = ipv4_sendpacket(newbuff, size + sizeof(udpframe_t), ip, IPV4_PROTO_UDP, broadcastnetdev);
|
||||||
|
|
||||||
|
leave:
|
||||||
free(newbuff);
|
free(newbuff);
|
||||||
return e;
|
return error;
|
||||||
}
|
}
|
||||||
|
|
||||||
void udp_init() {
|
void udp_init() {
|
||||||
@@ -163,12 +167,8 @@ static int internalpoll(socket_t *socket, polldata_t *data, int events) {
|
|||||||
int revents = 0;
|
int revents = 0;
|
||||||
|
|
||||||
if (events & POLLIN) {
|
if (events & POLLIN) {
|
||||||
bool intstate = interrupt_set(false);
|
|
||||||
spinlock_acquire(&udpsocket->ringbufferlock);
|
|
||||||
if (RINGBUFFER_DATACOUNT(&udpsocket->ringbuffer) > 0)
|
if (RINGBUFFER_DATACOUNT(&udpsocket->ringbuffer) > 0)
|
||||||
revents |= POLLIN;
|
revents |= POLLIN;
|
||||||
spinlock_release(&udpsocket->ringbufferlock);
|
|
||||||
interrupt_set(intstate);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (events & POLLOUT)
|
if (events & POLLOUT)
|
||||||
@@ -259,29 +259,31 @@ static int udp_recv(socket_t *socket, sockdesc_t *sockdesc) {
|
|||||||
MUTEX_ACQUIRE(&socket->mutex, false);
|
MUTEX_ACQUIRE(&socket->mutex, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool intstate = interrupt_set(false);
|
// this abuses an asterisk on the ringbuffer implementation that makes it not need locking when
|
||||||
spinlock_acquire(&udpsocket->ringbufferlock);
|
// something is reading and something is writing simultaneously.
|
||||||
|
// this is done to not need to disable interrupts as the ringbuffer_peek could take a fault
|
||||||
// TODO rewrite this to handle a possible sleep in the ringbuffer
|
// multiple readers cannot happen because of the socket mutex and the write on the side of the
|
||||||
|
// NIC is protected by the ringbuffer lock
|
||||||
size_t copycount;
|
size_t copycount;
|
||||||
dataheader_t header;
|
dataheader_t header;
|
||||||
if (flags & SOCKET_RECV_FLAGS_PEEK) {
|
|
||||||
__assert(ringbuffer_peek(&udpsocket->ringbuffer, &header, 0, sizeof(header)) == sizeof(header));
|
|
||||||
copycount = min(header.length, sockdesc->count);
|
|
||||||
|
|
||||||
__assert(ringbuffer_peek(&udpsocket->ringbuffer, sockdesc->buffer, sizeof(header), copycount) == copycount);
|
__assert(ringbuffer_peek(&udpsocket->ringbuffer, &header, 0, sizeof(header)) == sizeof(header));
|
||||||
} else {
|
copycount = min(header.length, sockdesc->count);
|
||||||
__assert(ringbuffer_read(&udpsocket->ringbuffer, &header, sizeof(header)) == sizeof(header));
|
|
||||||
|
|
||||||
copycount = min(header.length, sockdesc->count);
|
sockdesc->donecount = ringbuffer_peek(&udpsocket->ringbuffer, sockdesc->buffer, sizeof(header), copycount);
|
||||||
__assert(ringbuffer_read(&udpsocket->ringbuffer, sockdesc->buffer, copycount) == copycount);
|
if (sockdesc->donecount == RINGBUFFER_USER_COPY_FAILED) {
|
||||||
|
e = EFAULT;
|
||||||
// truncate the rest if the buffer wasn't big enough to handle everything
|
goto cleanup;
|
||||||
if (header.length > sockdesc->count)
|
}
|
||||||
ringbuffer_truncate(&udpsocket->ringbuffer, header.length - copycount);
|
|
||||||
|
__assert(sockdesc->donecount == copycount);
|
||||||
|
|
||||||
|
// remove the message if not asked to peek
|
||||||
|
if ((flags & SOCKET_RECV_FLAGS_PEEK) == 0) {
|
||||||
|
bool status = spinlock_acquireirqclear(&udpsocket->ringbufferlock);
|
||||||
|
ringbuffer_truncate(&udpsocket->ringbuffer, sizeof(header) + header.length);
|
||||||
|
spinlock_releaseirqrestore(&udpsocket->ringbufferlock, status);
|
||||||
}
|
}
|
||||||
spinlock_release(&udpsocket->ringbufferlock);
|
|
||||||
interrupt_set(intstate);
|
|
||||||
|
|
||||||
sockdesc->donecount = copycount;
|
sockdesc->donecount = copycount;
|
||||||
sockdesc->addr->ipv4addr.addr = header.peer;
|
sockdesc->addr->ipv4addr.addr = header.peer;
|
||||||
|
|||||||
@@ -68,7 +68,7 @@ size_t ringbuffer_peek(ringbuffer_t *ringbuffer, void *buffer, uintmax_t offset,
|
|||||||
return count;
|
return count;
|
||||||
|
|
||||||
if (USERCOPY_POSSIBLY_TO_USER((void *)((uintptr_t)buffer + firstpasscount), ringbuffer->data, count - firstpasscount))
|
if (USERCOPY_POSSIBLY_TO_USER((void *)((uintptr_t)buffer + firstpasscount), ringbuffer->data, count - firstpasscount))
|
||||||
return -RINGBUFFER_USER_COPY_FAILED;
|
return RINGBUFFER_USER_COPY_FAILED;
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user