create_port() incremented the used ports counter twice, thanks to Stefano

Ceccherini for the hint.
The first port ID is now 1 and not 0 anymore.
Added a first free slot hint to speed up port creation.
Added more debug output when tracing is enabled.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@10260 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2004-11-27 12:03:48 +00:00
parent 50edebb6cb
commit 515d213528
+70 -42
View File
@@ -1,12 +1,13 @@
/*
* Copyright 2002-2004, Axel Dörfler, [email protected].
* Distributed under the terms of the MIT License.
*
* Copyright 2001, Mark-Jan Bastian. All rights reserved.
* Distributed under the terms of the NewOS License.
*/
/* ports for IPC */
/*
** Copyright 2002-2004, The OpenBeOS Team. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
**
** Copyright 2001, Mark-Jan Bastian. All rights reserved.
** Distributed under the terms of the NewOS License.
*/
#include <OS.h>
@@ -64,7 +65,8 @@ static int32 sUsedPorts = 0;
static struct port_entry *sPorts = NULL;
static area_id sPortArea = 0;
static bool sPortsActive = false;
static port_id sNextPort = 0;
static port_id sNextPort = 1;
static int32 sFirstFreeSlot = 1;
static spinlock sPortSpinlock = 0;
@@ -293,6 +295,8 @@ delete_owned_ports(team_id owner)
int i;
int count = 0;
TRACE(("delete_owned_ports(owner = %ld)\n", owner));
if (!sPortsActive)
return B_BAD_PORT_ID;
@@ -378,9 +382,11 @@ create_port(int32 queueLength, const char *name)
cpu_status state;
char nameBuffer[B_OS_NAME_LENGTH];
sem_id readSem, writeSem;
port_id returnValue;
status_t status;
team_id owner;
int i;
int32 slot;
TRACE(("create_port(queueLength = %ld, name = \"%s\")\n", queueLength, name));
if (!sPortsActive)
return B_BAD_PORT_ID;
@@ -392,8 +398,8 @@ create_port(int32 queueLength, const char *name)
// check early on if there are any free port slots to use
if (atomic_add(&sUsedPorts, 1) >= sMaxPorts) {
atomic_add(&sUsedPorts, -1);
return B_NO_MORE_PORTS;
status = B_NO_MORE_PORTS;
goto err1;
}
// check & dup name
@@ -404,28 +410,23 @@ create_port(int32 queueLength, const char *name)
strlcpy(nameBuffer, name, B_OS_NAME_LENGTH);
name = strdup(nameBuffer);
if (name == NULL) {
atomic_add(&sUsedPorts, -1);
return B_NO_MEMORY;
status = B_NO_MEMORY;
goto err1;
}
// create read sem with owner set to -1
// ToDo: should be B_SYSTEM_TEAM
readSem = create_sem_etc(0, name, -1);
if (readSem < B_OK) {
// cleanup
free((char *)name);
atomic_add(&sUsedPorts, -1);
return readSem;
status = readSem;
goto err2;
}
// create write sem
writeSem = create_sem_etc(queueLength, name, -1);
if (writeSem < 0) {
// cleanup
delete_sem(readSem);
free((char *)name);
atomic_add(&sUsedPorts, -1);
return writeSem;
if (writeSem < B_OK) {
status = writeSem;
goto err3;
}
owner = team_get_current_team_id();
@@ -434,17 +435,21 @@ create_port(int32 queueLength, const char *name)
GRAB_PORT_LIST_LOCK();
// find the first empty spot
for (i = 0; i < sMaxPorts; i++) {
for (slot = 0; slot < sMaxPorts; slot++) {
int32 i = (slot + sFirstFreeSlot) % sMaxPorts;
if (sPorts[i].id == -1) {
port_id id;
// make the port_id be a multiple of the slot it's in
if (i >= sNextPort % sMaxPorts)
sNextPort += i - sNextPort % sMaxPorts;
else
sNextPort += sMaxPorts - (sNextPort % sMaxPorts - i);
sFirstFreeSlot = slot + 1;
GRAB_PORT_LOCK(sPorts[i]);
sPorts[i].id = sNextPort++;
atomic_add(&sUsedPorts, 1);
RELEASE_PORT_LIST_LOCK();
sPorts[i].capacity = queueLength;
@@ -456,33 +461,36 @@ create_port(int32 queueLength, const char *name)
list_init(&sPorts[i].msg_queue);
sPorts[i].total_count = 0;
returnValue = sPorts[i].id;
id = sPorts[i].id;
RELEASE_PORT_LOCK(sPorts[i]);
goto out;
restore_interrupts(state);
return id;
}
}
// not enough ports...
// ToDo: due to sUsedPorts, this cannot happen anymore - as
// long as sMaxPorts stays constant over the kernel run
// time (which it should be). IOW we could simply panic()
// here.
// not enough ports...
RELEASE_PORT_LIST_LOCK();
returnValue = B_NO_MORE_PORTS;
dprintf("create_port(): B_NO_MORE_PORTS\n");
// cleanup
delete_sem(writeSem);
delete_sem(readSem);
free((char *)name);
atomic_add(&sUsedPorts, -1);
out:
restore_interrupts(state);
return returnValue;
status = B_NO_MORE_PORTS;
delete_sem(writeSem);
err3:
delete_sem(readSem);
err2:
free((char *)name);
err1:
atomic_add(&sUsedPorts, -1);
return status;
}
@@ -492,6 +500,8 @@ close_port(port_id id)
cpu_status state;
int slot;
TRACE(("close_port(id = %ld)\n", id));
if (!sPortsActive || id < 0)
return B_BAD_PORT_ID;
@@ -528,6 +538,8 @@ delete_port(port_id id)
port_msg *msg;
int slot;
TRACE(("delete_port(id = %ld)\n", id));
if (!sPortsActive || id < 0)
return B_BAD_PORT_ID;
@@ -539,7 +551,8 @@ delete_port(port_id id)
if (sPorts[slot].id != id) {
RELEASE_PORT_LOCK(sPorts[slot]);
restore_interrupts(state);
dprintf("delete_port: invalid port_id %ld\n", id);
TRACE(("delete_port: invalid port_id %ld\n", id));
return B_BAD_PORT_ID;
}
@@ -552,6 +565,13 @@ delete_port(port_id id)
list_move_to_list(&sPorts[slot].msg_queue, &list);
RELEASE_PORT_LOCK(sPorts[slot]);
// update the first free slot hint in the array
GRAB_PORT_LIST_LOCK();
if (slot < sFirstFreeSlot)
sFirstFreeSlot = slot;
RELEASE_PORT_LIST_LOCK();
restore_interrupts(state);
atomic_add(&sUsedPorts, -1);
@@ -579,6 +599,8 @@ find_port(const char *name)
cpu_status state;
int i;
TRACE(("find_port(name = \"%s\")\n", name));
if (!sPortsActive)
return B_NAME_NOT_FOUND;
if (name == NULL)
@@ -636,6 +658,8 @@ _get_port_info(port_id id, port_info *info, size_t size)
cpu_status state;
int slot;
TRACE(("get_port_info(id = %ld)\n", id));
if (info == NULL || size != sizeof(port_info))
return B_BAD_VALUE;
if (!sPortsActive || id < 0)
@@ -669,6 +693,8 @@ _get_next_port_info(team_id team, int32 *_cookie, struct port_info *info, size_t
cpu_status state;
int slot;
TRACE(("get_next_port_info(team = %ld)\n", team));
if (info == NULL || size != sizeof(port_info) || _cookie == NULL || team < B_OK)
return B_BAD_VALUE;
if (!sPortsActive)
@@ -1053,6 +1079,8 @@ set_port_owner(port_id id, team_id team)
cpu_status state;
int slot;
TRACE(("set_port_owner(id = %ld, team = %ld)\n", id, team));
if (!sPortsActive || id < 0)
return B_BAD_PORT_ID;