* Closing a port now also deletes the port's semaphores, so that a pending write_port(),

read_port() or port_buffer_size() will fail immediately.
* Made the functions above plus port_count() support this new way of closing
  a port.
* All of Marcus's port tests now succeed.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16655 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2006-03-08 17:09:20 +00:00
parent 33a9adb376
commit 4d664f91ca
+52 -34
View File
@@ -389,8 +389,7 @@ port_used_ports(void)
} }
// #pragma mark - // #pragma mark - public kernel API
// public kernel API
port_id port_id
@@ -516,8 +515,9 @@ err1:
status_t status_t
close_port(port_id id) close_port(port_id id)
{ {
sem_id readSem, writeSem;
cpu_status state; cpu_status state;
int slot; int32 slot;
TRACE(("close_port(id = %ld)\n", id)); TRACE(("close_port(id = %ld)\n", id));
@@ -537,12 +537,18 @@ close_port(port_id id)
return B_BAD_PORT_ID; return B_BAD_PORT_ID;
} }
// mark port to disable writing // mark port to disable writing - deleting the semaphores will
// wake up waiting read/writes
sPorts[slot].capacity = 0; sPorts[slot].capacity = 0;
readSem = sPorts[slot].read_sem;
writeSem = sPorts[slot].write_sem;
RELEASE_PORT_LOCK(sPorts[slot]); RELEASE_PORT_LOCK(sPorts[slot]);
restore_interrupts(state); restore_interrupts(state);
delete_sem(readSem);
delete_sem(writeSem);
return B_NO_ERROR; return B_NO_ERROR;
} }
@@ -555,7 +561,7 @@ delete_port(port_id id)
const char *name; const char *name;
struct list list; struct list list;
port_msg *msg; port_msg *msg;
int slot; int32 slot;
TRACE(("delete_port(id = %ld)\n", id)); TRACE(("delete_port(id = %ld)\n", id));
@@ -616,7 +622,7 @@ find_port(const char *name)
{ {
port_id portFound = B_NAME_NOT_FOUND; port_id portFound = B_NAME_NOT_FOUND;
cpu_status state; cpu_status state;
int i; int32 i;
TRACE(("find_port(name = \"%s\")\n", name)); TRACE(("find_port(name = \"%s\")\n", name));
@@ -771,7 +777,7 @@ port_buffer_size_etc(port_id id, uint32 flags, bigtime_t timeout)
status_t status; status_t status;
port_msg *msg; port_msg *msg;
ssize_t size; ssize_t size;
int slot; int32 slot;
if (!sPortsActive || id < 0) if (!sPortsActive || id < 0)
return B_BAD_PORT_ID; return B_BAD_PORT_ID;
@@ -798,13 +804,12 @@ port_buffer_size_etc(port_id id, uint32 flags, bigtime_t timeout)
// block if no message, or, if B_TIMEOUT flag set, block with timeout // block if no message, or, if B_TIMEOUT flag set, block with timeout
status = acquire_sem_etc(cachedSem, 1, flags, timeout); status = acquire_sem_etc(cachedSem, 1, flags, timeout);
if (status == B_BAD_SEM_ID) { if (status != B_OK && status != B_BAD_SEM_ID)
// somebody deleted the port
return B_BAD_PORT_ID;
}
if (status != B_OK)
return status; return status;
// in case of B_BAD_SEM_ID, the port might have been closed but not yet
// deleted, ie. there could still be messages waiting for us
state = disable_interrupts(); state = disable_interrupts();
GRAB_PORT_LOCK(sPorts[slot]); GRAB_PORT_LOCK(sPorts[slot]);
@@ -817,10 +822,13 @@ port_buffer_size_etc(port_id id, uint32 flags, bigtime_t timeout)
// determine tail & get the length of the message // determine tail & get the length of the message
msg = list_get_first_item(&sPorts[slot].msg_queue); msg = list_get_first_item(&sPorts[slot].msg_queue);
if (msg == NULL) if (msg == NULL) {
panic("port %ld: no messages found\n", sPorts[slot].id); if (status == B_OK)
panic("port %ld: no messages found\n", sPorts[slot].id);
size = msg->size; size = B_BAD_PORT_ID;
} else
size = msg->size;
RELEASE_PORT_LOCK(sPorts[slot]); RELEASE_PORT_LOCK(sPorts[slot]);
restore_interrupts(state); restore_interrupts(state);
@@ -837,8 +845,8 @@ ssize_t
port_count(port_id id) port_count(port_id id)
{ {
cpu_status state; cpu_status state;
int32 count; int32 count = 0;
int slot; int32 slot;
if (!sPortsActive || id < 0) if (!sPortsActive || id < 0)
return B_BAD_PORT_ID; return B_BAD_PORT_ID;
@@ -855,15 +863,22 @@ port_count(port_id id)
return B_BAD_PORT_ID; return B_BAD_PORT_ID;
} }
get_sem_count(sPorts[slot].read_sem, &count); if (get_sem_count(sPorts[slot].read_sem, &count) == B_OK) {
// do not return negative numbers // do not return negative numbers
if (count < 0) if (count < 0)
count = 0; count = 0;
} else {
// the port might have been closed - we need to actually count the messages
void *message = NULL;
while ((message = list_get_next_item(&sPorts[slot].msg_queue, message)) != NULL) {
count++;
}
}
RELEASE_PORT_LOCK(sPorts[slot]); RELEASE_PORT_LOCK(sPorts[slot]);
restore_interrupts(state); restore_interrupts(state);
// return count of messages (sem_count) // return count of messages
return count; return count;
} }
@@ -920,13 +935,12 @@ read_port_etc(port_id id, int32 *_msgCode, void *msgBuffer, size_t bufferSize,
status = acquire_sem_etc(cachedSem, 1, flags, timeout); status = acquire_sem_etc(cachedSem, 1, flags, timeout);
// get 1 entry from the queue, block if needed // get 1 entry from the queue, block if needed
if (status == B_BAD_SEM_ID) { if (status != B_OK && status != B_BAD_SEM_ID)
// somebody deleted the port
return B_BAD_PORT_ID;
}
if (status != B_OK)
return status; return status;
// in case of B_BAD_SEM_ID, the port might have been closed but not yet
// deleted, ie. there could still be messages waiting for us
state = disable_interrupts(); state = disable_interrupts();
GRAB_PORT_LOCK(sPorts[slot]); GRAB_PORT_LOCK(sPorts[slot]);
@@ -939,8 +953,15 @@ read_port_etc(port_id id, int32 *_msgCode, void *msgBuffer, size_t bufferSize,
} }
msg = list_get_first_item(&sPorts[slot].msg_queue); msg = list_get_first_item(&sPorts[slot].msg_queue);
if (msg == NULL) if (msg == NULL) {
panic("port %ld: no messages found", sPorts[slot].id); if (status == B_OK)
panic("port %ld: no messages found", sPorts[slot].id);
// the port has obviously been closed, but no messages are left anymore
RELEASE_PORT_LOCK(sPorts[slot]);
restore_interrupts(state);
return B_BAD_PORT_ID;
}
list_remove_link(msg); list_remove_link(msg);
@@ -1047,7 +1068,7 @@ writev_port_etc(port_id id, int32 msgCode, const iovec *msgVecs,
// get 1 entry from the queue, block if needed // get 1 entry from the queue, block if needed
if (status == B_BAD_SEM_ID) { if (status == B_BAD_SEM_ID) {
// somebody deleted the port // somebody deleted or closed the port
return B_BAD_PORT_ID; return B_BAD_PORT_ID;
} }
if (status != B_OK) if (status != B_OK)
@@ -1156,10 +1177,7 @@ set_port_owner(port_id id, team_id team)
} }
// #pragma mark - // #pragma mark - syscalls
/*
* user level ports
*/
port_id port_id