[haiku-commits] r33728 - in haiku/trunk: headers/private/kernel src/system/kernel src/system/kernel/util

  • From: axeld@xxxxxxxxxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Thu, 22 Oct 2009 15:24:12 +0200 (CEST)

Author: axeld
Date: 2009-10-22 15:24:12 +0200 (Thu, 22 Oct 2009)
New Revision: 33728
Changeset: http://dev.haiku-os.org/changeset/33728/haiku

Removed:
   haiku/trunk/headers/private/kernel/cbuf.h
   haiku/trunk/src/system/kernel/util/cbuf.c
Modified:
   haiku/trunk/src/system/kernel/main.cpp
   haiku/trunk/src/system/kernel/port.cpp
   haiku/trunk/src/system/kernel/util/Jamfile
Log:
Basically rewrote the ports subsystem to use:
* its own heap allocator instead of cbuf - this makes cbuf superfluous, and I
  therefore removed it from the kernel. The heap is swappable, so lifts the
  kernel's resource usage a bit. In the future, the heap should grow as well;
  right now it should be at least as good as before.
* it no longer uses spinlocks, but just mutexes now for better scalability - it
  was not usable with interrupts turned off anyway (due to its semaphore usage).
* it no longer uses semaphores, but condition variables.
* Needed to move the port initialization to a later point, as swappable memory
  wasn't usable that early.
* All ports test are still passing, hopefully I didn't mess anything up :-)


Modified: haiku/trunk/src/system/kernel/main.cpp
===================================================================
--- haiku/trunk/src/system/kernel/main.cpp      2009-10-22 13:14:32 UTC (rev 
33727)
+++ haiku/trunk/src/system/kernel/main.cpp      2009-10-22 13:24:12 UTC (rev 
33728)
@@ -1,5 +1,5 @@
 /*
- * Copyright 2002-2008, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx
+ * Copyright 2002-2009, Axel Dörfler, axeld@xxxxxxxxxxxxxxxxx
  * Distributed under the terms of the MIT License.
  *
  * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
@@ -18,7 +18,6 @@
 #include <boot_device.h>
 #include <boot_item.h>
 #include <boot_splash.h>
-#include <cbuf.h>
 #include <commpage.h>
 #include <condition_variable.h>
 #include <cpu.h>
@@ -163,21 +162,13 @@
                TRACE("init generic syscall\n");
                generic_syscall_init();
                smp_init_post_generic_syscalls();
-               TRACE("init cbuf\n");
-               cbuf_init();
                TRACE("init scheduler\n");
                scheduler_init();
                TRACE("init threads\n");
                thread_init(&sKernelArgs);
-               TRACE("init ports\n");
-               port_init(&sKernelArgs);
                TRACE("init kernel daemons\n");
                kernel_daemon_init();
                arch_platform_init_post_thread(&sKernelArgs);
-               TRACE("init POSIX semaphores\n");
-               realtime_sem_init();
-               xsi_sem_init();
-               xsi_msg_init();
 
                TRACE("init VM threads\n");
                vm_init_post_thread(&sKernelArgs);
@@ -188,6 +179,10 @@
                TRACE("init swap support\n");
                swap_init();
 #endif
+               TRACE("init POSIX semaphores\n");
+               realtime_sem_init();
+               xsi_sem_init();
+               xsi_msg_init();
 
                // Start a thread to finish initializing the rest of the 
system. Note,
                // it won't be scheduled before calling scheduler_start() (on 
any CPU).
@@ -251,6 +246,9 @@
 
        commpage_init_post_cpus();
 
+       TRACE("init ports\n");
+       port_init(&sKernelArgs);
+
        TRACE("Init modules\n");
        boot_splash_set_stage(BOOT_SPLASH_STAGE_1_INIT_MODULES);
        module_init_post_threads();

Modified: haiku/trunk/src/system/kernel/port.cpp
===================================================================
--- haiku/trunk/src/system/kernel/port.cpp      2009-10-22 13:14:32 UTC (rev 
33727)
+++ haiku/trunk/src/system/kernel/port.cpp      2009-10-22 13:24:12 UTC (rev 
33728)
@@ -18,7 +18,7 @@
 #include <OS.h>
 
 #include <arch/int.h>
-#include <cbuf.h>
+#include <heap.h>
 #include <kernel.h>
 #include <Notifications.h>
 #include <sem.h>
@@ -37,27 +37,30 @@
 #endif
 
 
-typedef struct port_msg {
-       list_link       link;
-       int32           code;
-       cbuf            *buffer_chain;
-       size_t          size;
-       uid_t           sender;
-       gid_t           sender_group;
-       team_id         sender_team;
-} port_msg;
+struct port_message : DoublyLinkedListLinkImpl<port_message> {
+       int32                           code;
+       size_t                          size;
+       uid_t                           sender;
+       gid_t                           sender_group;
+       team_id                         sender_team;
+       char                            buffer[0];
+};
 
+typedef DoublyLinkedList<port_message> MessageList;
+
 struct port_entry {
-       port_id         id;
-       team_id         owner;
-       int32           capacity;
-       spinlock        lock;
-       const char      *name;
-       sem_id          read_sem;
-       sem_id          write_sem;
-       int32           total_count;    // messages read from port since 
creation
-       select_info     *select_infos;
-       struct list     msg_queue;
+       port_id                         id;
+       team_id                         owner;
+       int32                           capacity;
+       mutex                           lock;
+       int32                           read_count;
+       int32                           write_count;
+       ConditionVariable       read_condition;
+       ConditionVariable       write_condition;
+       int32                           total_count;
+               // messages read from port since creation
+       select_info*            select_infos;
+       MessageList                     messages;
 };
 
 class PortNotificationService : public DefaultNotificationService {
@@ -67,6 +70,7 @@
                        void                    Notify(uint32 opcode, port_id 
team);
 };
 
+static const size_t kInitialPortBufferSize = 4 * 1024 * 1024;
 #define MAX_QUEUE_LENGTH 4096
 #define PORT_MAX_MESSAGE_SIZE (256 * 1024)
 
@@ -74,27 +78,23 @@
 static int32 sMaxPorts = 4096;
 static int32 sUsedPorts = 0;
 
-static struct port_entry *sPorts = NULL;
-static area_id sPortArea = 0;
+static struct port_entry* sPorts;
+static area_id sPortArea;
+static heap_allocator* sPortAllocator;
 static bool sPortsActive = false;
 static port_id sNextPort = 1;
 static int32 sFirstFreeSlot = 1;
+static mutex sPortsLock = MUTEX_INITIALIZER("ports list");
 
 static PortNotificationService sNotificationService;
 
-static spinlock sPortSpinlock = B_SPINLOCK_INITIALIZER;
 
-#define GRAB_PORT_LIST_LOCK() acquire_spinlock(&sPortSpinlock)
-#define RELEASE_PORT_LIST_LOCK() release_spinlock(&sPortSpinlock)
-#define GRAB_PORT_LOCK(s) acquire_spinlock(&(s).lock)
-#define RELEASE_PORT_LOCK(s) release_spinlock(&(s).lock)
-
-
 //     #pragma mark - TeamNotificationService
 
 
 PortNotificationService::PortNotificationService()
-       : DefaultNotificationService("ports")
+       :
+       DefaultNotificationService("ports")
 {
 }
 
@@ -116,9 +116,9 @@
 
 
 static int
-dump_port_list(int argc, char **argv)
+dump_port_list(int argc, char** argv)
 {
-       const char *name = NULL;
+       const char* name = NULL;
        team_id owner = -1;
        int32 i;
 
@@ -130,58 +130,48 @@
        } else if (argc > 1)
                owner = strtoul(argv[1], NULL, 0);
 
-       kprintf("port             id  cap  r-sem  r-cnt  w-sem  w-cnt    total  
 team  name\n");
+       kprintf("port             id  cap  read-cnt  write-cnt   total   team  "
+               "name\n");
 
        for (i = 0; i < sMaxPorts; i++) {
-               struct port_entry *port = &sPorts[i];
+               struct port_entry* port = &sPorts[i];
                if (port->id < 0
                        || (owner != -1 && port->owner != owner)
-                       || (name != NULL && strstr(port->name, name) == NULL))
+                       || (name != NULL && strstr(port->lock.name, name) == 
NULL))
                        continue;
 
-               int32 readCount, writeCount;
-               get_sem_count(port->read_sem, &readCount);
-               get_sem_count(port->write_sem, &writeCount);
-               kprintf("%p %8ld %4ld %6ld %6ld %6ld %6ld %8ld %6ld  %s\n", 
port,
-                       port->id, port->capacity, port->read_sem, readCount,
-                       port->write_sem, writeCount, port->total_count, 
port->owner,
-                       port->name);
+               kprintf("%p %8ld %4ld %9ld %9ld %8ld %6ld  %s\n", port,
+                       port->id, port->capacity, port->read_count, 
port->write_count,
+                       port->total_count, port->owner, port->lock.name);
        }
+
        return 0;
 }
 
 
 static void
-_dump_port_info(struct port_entry *port)
+_dump_port_info(struct port_entry* port)
 {
-       int32 count;
-
        kprintf("PORT: %p\n", port);
        kprintf(" id:              %ld\n", port->id);
-       kprintf(" name:            \"%s\"\n", port->name);
+       kprintf(" name:            \"%s\"\n", port->lock.name);
        kprintf(" owner:           %ld\n", port->owner);
        kprintf(" capacity:        %ld\n", port->capacity);
-       kprintf(" read_sem:        %ld\n", port->read_sem);
-       kprintf(" write_sem:       %ld\n", port->write_sem);
-       get_sem_count(port->read_sem, &count);
-       kprintf(" read_sem count:  %ld\n", count);
-       get_sem_count(port->write_sem, &count);
-       kprintf(" write_sem count: %ld\n", count);
+       kprintf(" read_count:      %ld\n", port->read_count);
+       kprintf(" write_count:     %ld\n", port->write_count);
        kprintf(" total count:     %ld\n", port->total_count);
 
        set_debug_variable("_port", (addr_t)port);
        set_debug_variable("_portID", port->id);
        set_debug_variable("_owner", port->owner);
-       set_debug_variable("_readSem", port->read_sem);
-       set_debug_variable("_writeSem", port->write_sem);
 }
 
 
 static int
-dump_port_info(int argc, char **argv)
+dump_port_info(int argc, char** argv)
 {
-       const char *name = NULL;
-       sem_id sem = -1;
+       const char* name = NULL;
+       ConditionVariable* condition = NULL;
        int i;
 
        if (argc < 2) {
@@ -191,10 +181,10 @@
 
        if (argc > 2) {
                if (!strcmp(argv[1], "address")) {
-                       _dump_port_info((struct port_entry *)strtoul(argv[2], 
NULL, 0));
+                       _dump_port_info((struct port_entry*)strtoul(argv[2], 
NULL, 0));
                        return 0;
-               } else if (!strcmp(argv[1], "sem"))
-                       sem = strtoul(argv[2], NULL, 0);
+               } else if (!strcmp(argv[1], "condition"))
+                       condition = (ConditionVariable*)strtoul(argv[2], NULL, 
0);
                else if (!strcmp(argv[1], "name"))
                        name = argv[2];
        } else if (isdigit(argv[1][0])) {
@@ -212,10 +202,10 @@
 
        // walk through the ports list, trying to match name
        for (i = 0; i < sMaxPorts; i++) {
-               if ((name != NULL && sPorts[i].name != NULL
-                               && !strcmp(name, sPorts[i].name))
-                       || (sem != -1 && (sPorts[i].read_sem == sem
-                               || sPorts[i].write_sem == sem))) {
+               if ((name != NULL && sPorts[i].lock.name != NULL
+                               && !strcmp(name, sPorts[i].lock.name))
+                       || (condition != NULL && (&sPorts[i].read_condition == 
condition
+                               || &sPorts[i].write_condition == condition))) {
                        _dump_port_info(&sPorts[i]);
                        return 0;
                }
@@ -234,35 +224,26 @@
 
 
 static void
-put_port_msg(port_msg *msg)
+put_port_message(port_message* message)
 {
-       cbuf_free_chain(msg->buffer_chain);
-       free(msg);
+       heap_free(sPortAllocator, message);
 }
 
 
-static port_msg *
-get_port_msg(int32 code, size_t bufferSize)
+static port_message*
+get_port_message(int32 code, size_t bufferSize)
 {
-       // ToDo: investigate preallocation of port_msgs (or use a slab 
allocator)
-       cbuf *bufferChain = NULL;
-
-       port_msg *msg = (port_msg *)malloc(sizeof(port_msg));
-       if (msg == NULL)
+       port_message* message = (port_message*)heap_memalign(sPortAllocator,
+               0, sizeof(port_message) + bufferSize);
+       if (message == NULL) {
+               // TODO: add another heap area until we ran into some limit
                return NULL;
-
-       if (bufferSize > 0) {
-               bufferChain = cbuf_get_chain(bufferSize);
-               if (bufferChain == NULL) {
-                       free(msg);
-                       return NULL;
-               }
        }
 
-       msg->code = code;
-       msg->buffer_chain = bufferChain;
-       msg->size = bufferSize;
-       return msg;
+       message->code = code;
+       message->size = bufferSize;
+
+       return message;
 }
 
 
@@ -279,25 +260,47 @@
        The port lock must be held when called.
 */
 static void
-fill_port_info(struct port_entry *port, port_info *info, size_t size)
+fill_port_info(struct port_entry* port, port_info* info, size_t size)
 {
-       int32 count;
-
        info->port = port->id;
        info->team = port->owner;
        info->capacity = port->capacity;
 
-       get_sem_count(port->read_sem, &count);
+       int32 count = port->read_count;
        if (count < 0)
                count = 0;
 
        info->queue_count = count;
        info->total_count = port->total_count;
 
-       strlcpy(info->name, port->name, B_OS_NAME_LENGTH);
+       strlcpy(info->name, port->lock.name, B_OS_NAME_LENGTH);
 }
 
 
+static ssize_t
+copy_port_message(port_message* message, int32* _code, void* buffer,
+       size_t bufferSize, bool userCopy)
+{
+       // check output buffer size
+       size_t size = min_c(bufferSize, message->size);
+
+       // copy message
+       if (_code != NULL)
+               *_code = message->code;
+
+       if (size > 0) {
+               if (userCopy) {
+                       status_t status = user_memcpy(buffer, message->buffer, 
size);
+                       if (status != B_OK)
+                               return status;
+               } else
+                       memcpy(buffer, message->buffer, size);
+       }
+
+       return size;
+}
+
+
 //     #pragma mark - private kernel API
 
 
@@ -307,38 +310,28 @@
 int
 delete_owned_ports(team_id owner)
 {
-       // ToDo: investigate maintaining a list of ports in the team
+       // TODO: investigate maintaining a list of ports in the team
        //      to make this simpler and more efficient.
-       cpu_status state;
-       int i;
-       int count = 0;
 
        TRACE(("delete_owned_ports(owner = %ld)\n", owner));
 
-       if (!sPortsActive)
-               return B_BAD_PORT_ID;
+       MutexLocker locker(sPortsLock);
 
-       state = disable_interrupts();
-       GRAB_PORT_LIST_LOCK();
+       int32 count = 0;
 
-       for (i = 0; i < sMaxPorts; i++) {
+       for (int32 i = 0; i < sMaxPorts; i++) {
                if (sPorts[i].id != -1 && sPorts[i].owner == owner) {
                        port_id id = sPorts[i].id;
 
-                       RELEASE_PORT_LIST_LOCK();
-                       restore_interrupts(state);
+                       locker.Unlock();
 
                        delete_port(id);
                        count++;
 
-                       state = disable_interrupts();
-                       GRAB_PORT_LIST_LOCK();
+                       locker.Lock();
                }
        }
 
-       RELEASE_PORT_LIST_LOCK();
-       restore_interrupts(state);
-
        return count;
 }
 
@@ -361,24 +354,38 @@
 port_init(kernel_args *args)
 {
        size_t size = sizeof(struct port_entry) * sMaxPorts;
-       int32 i;
 
        // create and initialize ports table
-       sPortArea = create_area("port_table", (void **)&sPorts, 
B_ANY_KERNEL_ADDRESS,
-               size, B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
+       sPortArea = create_area("port_table",
+               (void**)&sPorts, B_ANY_KERNEL_ADDRESS, size, B_FULL_LOCK,
+               B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
        if (sPortArea < 0) {
                panic("unable to allocate kernel port table!\n");
                return sPortArea;
        }
 
-       // ToDo: investigate preallocating a list of port_msgs to
-       //      speed up actual message sending/receiving, a slab allocator
-       //      might do it as well, though :-)
-
        memset(sPorts, 0, size);
-       for (i = 0; i < sMaxPorts; i++)
+       for (int32 i = 0; i < sMaxPorts; i++) {
+               mutex_init(&sPorts[i].lock, NULL);
                sPorts[i].id = -1;
+               sPorts[i].read_condition.Init(&sPorts[i], "port read");
+               sPorts[i].write_condition.Init(&sPorts[i], "port write");
+       }
 
+       addr_t base;
+       if (create_area("port heap", (void**)&base, B_ANY_KERNEL_ADDRESS,
+                       kInitialPortBufferSize, B_NO_LOCK,
+                       B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA) < 0) {
+               panic("unable to allocate port area!\n");
+               return B_ERROR;
+       }
+
+       static const heap_class kBufferHeapClass = {"default", 100,
+               PORT_MAX_MESSAGE_SIZE + sizeof(port_message), 2 * 1024,
+               sizeof(port_message), 8, 4, 64};
+       sPortAllocator = heap_create_allocator("port buffer", base,
+               kInitialPortBufferSize, &kBufferHeapClass, true);
+
        // add debugger commands
        add_debugger_command_etc("ports", &dump_port_list,
                "Dump a list of all active ports (for team, with name, etc.)",
@@ -406,71 +413,36 @@
 
 
 port_id
-create_port(int32 queueLength, const char *name)
+create_port(int32 queueLength, const char* name)
 {
-       cpu_status state;
-       char nameBuffer[B_OS_NAME_LENGTH];
-       sem_id readSem, writeSem;
-       status_t status;
-       team_id owner;
-       int32 slot;
-
        TRACE(("create_port(queueLength = %ld, name = \"%s\")\n", queueLength,
                name));
 
-       if (!sPortsActive)
+       if (!sPortsActive) {
+               panic("ports used too early!\n");
                return B_BAD_PORT_ID;
-
-       // check queue length
-       if (queueLength < 1
-               || queueLength > MAX_QUEUE_LENGTH)
+       }
+       if (queueLength < 1 || queueLength > MAX_QUEUE_LENGTH)
                return B_BAD_VALUE;
 
+       MutexLocker locker(sPortsLock);
+
        // check early on if there are any free port slots to use
-       if (atomic_add(&sUsedPorts, 1) >= sMaxPorts) {
-               status = B_NO_MORE_PORTS;
-               goto err1;
-       }
+       if (sUsedPorts >= sMaxPorts)
+               return B_NO_MORE_PORTS;
 
        // check & dup name
-       if (name == NULL)
-               name = "unnamed port";
+       char* nameBuffer = strdup(name != NULL ? name : "unnamed port");
+       if (nameBuffer == NULL)
+               return B_NO_MEMORY;
 
-       // ToDo: we could save the memory and use the semaphore name only 
instead
-       strlcpy(nameBuffer, name, B_OS_NAME_LENGTH);
-       name = strdup(nameBuffer);
-       if (name == NULL) {
-               status = B_NO_MEMORY;
-               goto err1;
-       }
+       sUsedPorts++;
 
-       // 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) {
-               status = readSem;
-               goto err2;
-       }
-
-       // create write sem
-       writeSem = create_sem_etc(queueLength, name, -1);
-       if (writeSem < B_OK) {
-               status = writeSem;
-               goto err3;
-       }
-
-       owner = team_get_current_team_id();
-
-       state = disable_interrupts();
-       GRAB_PORT_LIST_LOCK();
-
        // find the first empty spot
-       for (slot = 0; slot < sMaxPorts; slot++) {
+       for (int32 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;
@@ -478,24 +450,20 @@
                                sNextPort += sMaxPorts - (sNextPort % sMaxPorts 
- i);
                        sFirstFreeSlot = slot + 1;
 
-                       GRAB_PORT_LOCK(sPorts[i]);
+                       MutexLocker portLocker(sPorts[i].lock);
                        sPorts[i].id = sNextPort++;
-                       RELEASE_PORT_LIST_LOCK();
+                       locker.Unlock();
 
                        sPorts[i].capacity = queueLength;
-                       sPorts[i].owner = owner;
-                       sPorts[i].name = name;
-
-                       sPorts[i].read_sem      = readSem;
-                       sPorts[i].write_sem     = writeSem;
-
-                       list_init(&sPorts[i].msg_queue);
+                       sPorts[i].owner = team_get_current_team_id();
+                       sPorts[i].lock.name = nameBuffer;
+                       sPorts[i].read_count = 0;
+                       sPorts[i].write_count = queueLength;
                        sPorts[i].total_count = 0;
                        sPorts[i].select_infos = NULL;
-                       id = sPorts[i].id;
 
-                       RELEASE_PORT_LOCK(sPorts[i]);
-                       restore_interrupts(state);
+                       port_id id = sPorts[i].id;
+                       portLocker.Unlock();
 
                        TRACE(("create_port() done: port created %ld\n", id));
 
@@ -504,51 +472,27 @@
                }
        }
 
-       // 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.
-
-       RELEASE_PORT_LIST_LOCK();
-       restore_interrupts(state);
-
-       status = B_NO_MORE_PORTS;
-
-       delete_sem(writeSem);
-err3:
-       delete_sem(readSem);
-err2:
-       free((char *)name);
-err1:
-       atomic_add(&sUsedPorts, -1);
-
-       return status;
+       // Still not enough ports... - due to sUsedPorts, this cannot really
+       // happen anymore.
+       panic("out of ports, but sUsedPorts is broken");
+       return B_NO_MORE_PORTS;
 }
 
 
 status_t
 close_port(port_id id)
 {
-       sem_id readSem, writeSem;
-       cpu_status state;
-       int32 slot;
-
        TRACE(("close_port(id = %ld)\n", id));
 
        if (!sPortsActive || id < 0)
                return B_BAD_PORT_ID;
 
-       slot = id % sMaxPorts;
+       int32 slot = id % sMaxPorts;
 
        // walk through the sem list, trying to match name
-       state = disable_interrupts();
-       GRAB_PORT_LOCK(sPorts[slot]);
+       MutexLocker locker(sPorts[slot].lock);
 
        if (sPorts[slot].id != id) {
-               RELEASE_PORT_LOCK(sPorts[slot]);
-               restore_interrupts(state);
                TRACE(("close_port: invalid port_id %ld\n", id));
                return B_BAD_PORT_ID;
        }
@@ -556,160 +500,118 @@
        // mark port to disable writing - deleting the semaphores will
        // wake up waiting read/writes
        sPorts[slot].capacity = 0;
-       readSem = sPorts[slot].read_sem;
-       writeSem = sPorts[slot].write_sem;
 
        notify_port_select_events(slot, B_EVENT_INVALID);
        sPorts[slot].select_infos = NULL;
 
-       RELEASE_PORT_LOCK(sPorts[slot]);
-       restore_interrupts(state);
+       sPorts[slot].read_condition.NotifyAll(false, B_BAD_PORT_ID);
+       sPorts[slot].write_condition.NotifyAll(false, B_BAD_PORT_ID);
 
-       delete_sem(readSem);
-       delete_sem(writeSem);
-
-       return B_NO_ERROR;
+       return B_OK;
 }
 
 
 status_t
 delete_port(port_id id)
 {
-       cpu_status state;
-       sem_id readSem, writeSem;
-       const char *name;
-       struct list list;
-       port_msg *msg;
-       int32 slot;
-
        TRACE(("delete_port(id = %ld)\n", id));
 
        if (!sPortsActive || id < 0)
                return B_BAD_PORT_ID;
 
-       slot = id % sMaxPorts;
+       int32 slot = id % sMaxPorts;
 
-       state = disable_interrupts();
-       GRAB_PORT_LOCK(sPorts[slot]);
+       MutexLocker locker(sPorts[slot].lock);
 
        if (sPorts[slot].id != id) {
-               RELEASE_PORT_LOCK(sPorts[slot]);
-               restore_interrupts(state);
-
                TRACE(("delete_port: invalid port_id %ld\n", id));
                return B_BAD_PORT_ID;
        }
 
-       /* mark port as invalid */
+       // mark port as invalid
        sPorts[slot].id = -1;
-       name = sPorts[slot].name;
-       readSem = sPorts[slot].read_sem;
-       writeSem = sPorts[slot].write_sem;
-       sPorts[slot].name = NULL;
-       list_move_to_list(&sPorts[slot].msg_queue, &list);
+       free((char*)sPorts[slot].lock.name);
+       sPorts[slot].lock.name = NULL;
 
+       while (port_message* message = sPorts[slot].messages.RemoveHead()) {
+               put_port_message(message);
+       }
+
        notify_port_select_events(slot, B_EVENT_INVALID);
        sPorts[slot].select_infos = NULL;
 
-       RELEASE_PORT_LOCK(sPorts[slot]);
+       // Release the threads that were blocking on this port.
+       // read_port() will see the B_BAD_PORT_ID return value, and act 
accordingly
+       sPorts[slot].read_condition.NotifyAll(B_BAD_PORT_ID);
+       sPorts[slot].write_condition.NotifyAll(B_BAD_PORT_ID);
+       sNotificationService.Notify(PORT_REMOVED, id);
 
+       locker.Unlock();
+
+       MutexLocker _(sPortsLock);
+
        // 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);
-
-       // free the queue
-       while ((msg = (port_msg *)list_remove_head_item(&list)) != NULL) {
-               put_port_msg(msg);
-       }
-
-       free((char *)name);
-
-       // release the threads that were blocking on this port by deleting the 
sem
-       // read_port() will see the B_BAD_SEM_ID acq_sem() return value, and 
act accordingly
-       delete_sem(readSem);
-       delete_sem(writeSem);
-       sNotificationService.Notify(PORT_REMOVED, id);
-
+       sUsedPorts--;
        return B_OK;
 }
 
 
 status_t
-select_port(int32 id, struct select_info *info, bool kernel)
+select_port(int32 id, struct select_info* info, bool kernel)
 {
-       cpu_status state;
-       int32 slot;
-       status_t error = B_OK;
-
        if (id < 0)
                return B_BAD_PORT_ID;
 
-       slot = id % sMaxPorts;
+       int32 slot = id % sMaxPorts;
 
-       state = disable_interrupts();
-       GRAB_PORT_LOCK(sPorts[slot]);
+       MutexLocker locker(sPorts[slot].lock);
 
-       if (sPorts[slot].id != id || is_port_closed(slot)) {
-               // bad port ID
-               error = B_BAD_SEM_ID;
-       } else if (!kernel && sPorts[slot].owner == team_get_kernel_team_id()) {
+       if (sPorts[slot].id != id || is_port_closed(slot))
+               return B_BAD_PORT_ID;
+       if (!kernel && sPorts[slot].owner == team_get_kernel_team_id()) {
                // kernel port, but call from userland
-               error = B_NOT_ALLOWED;
-       } else {
-               info->selected_events &= B_EVENT_READ | B_EVENT_WRITE | 
B_EVENT_INVALID;
+               return B_NOT_ALLOWED;
+       }
 
-               if (info->selected_events != 0) {
-                       uint16 events = 0;
-                       int32 writeCount = 0;
+       info->selected_events &= B_EVENT_READ | B_EVENT_WRITE | B_EVENT_INVALID;
 
-                       info->next = sPorts[slot].select_infos;
-                       sPorts[slot].select_infos = info;
+       if (info->selected_events != 0) {
+               uint16 events = 0;
 
-                       // check for events
-                       if ((info->selected_events & B_EVENT_READ) != 0
-                               && !list_is_empty(&sPorts[slot].msg_queue)) {
-                               events |= B_EVENT_READ;
-                       }
+               info->next = sPorts[slot].select_infos;
+               sPorts[slot].select_infos = info;
 
-                       if (get_sem_count(sPorts[slot].write_sem, &writeCount) 
== B_OK
-                               && writeCount > 0) {
-                               events |= B_EVENT_WRITE;
-                       }
-
-                       if (events != 0)
-                               notify_select_events(info, events);
+               // check for events
+               if ((info->selected_events & B_EVENT_READ) != 0
+                       && !sPorts[slot].messages.IsEmpty()) {
+                       events |= B_EVENT_READ;
                }
-       }
 
-       RELEASE_PORT_LOCK(sPorts[slot]);
-       restore_interrupts(state);
+               if (sPorts[slot].write_count > 0)
+                       events |= B_EVENT_WRITE;
 
-       return error;
+               if (events != 0)
+                       notify_select_events(info, events);
+       }
+
+       return B_OK;
 }
 
 
 status_t
-deselect_port(int32 id, struct select_info *info, bool kernel)
+deselect_port(int32 id, struct select_info* info, bool kernel)
 {
-       cpu_status state;
-       int32 slot;
-
        if (id < 0)
                return B_BAD_PORT_ID;
-
        if (info->selected_events == 0)
                return B_OK;
 
-       slot = id % sMaxPorts;
+       int32 slot = id % sMaxPorts;
 
-       state = disable_interrupts();
-       GRAB_PORT_LOCK(sPorts[slot]);
+       MutexLocker locker(sPorts[slot].lock);
 
        if (sPorts[slot].id == id) {
                select_info** infoLocation = &sPorts[slot].select_infos;
@@ -720,24 +622,19 @@
                        *infoLocation = info->next;
        }
 
-       RELEASE_PORT_LOCK(sPorts[slot]);
-       restore_interrupts(state);
-
        return B_OK;
 }
 
 
 port_id
-find_port(const char *name)
+find_port(const char* name)
 {
-       port_id portFound = B_NAME_NOT_FOUND;
-       cpu_status state;
-       int32 i;
-
        TRACE(("find_port(name = \"%s\")\n", name));
 
-       if (!sPortsActive)
+       if (!sPortsActive) {
+               panic("ports used too early!\n");
                return B_NAME_NOT_FOUND;
+       }
        if (name == NULL)
                return B_BAD_VALUE;
 
@@ -746,28 +643,21 @@
        // the port lock in question, not the port list lock
 
        // loop over list
-       for (i = 0; i < sMaxPorts && portFound < B_OK; i++) {
+       for (int32 i = 0; i < sMaxPorts; i++) {
                // lock every individual port before comparing
-               state = disable_interrupts();
-               GRAB_PORT_LOCK(sPorts[i]);
+               MutexLocker _(sPorts[i].lock);
 
-               if (sPorts[i].id >= 0 && !strcmp(name, sPorts[i].name))
-                       portFound = sPorts[i].id;
-
-               RELEASE_PORT_LOCK(sPorts[i]);
-               restore_interrupts(state);
+               if (sPorts[i].id >= 0 && !strcmp(name, sPorts[i].lock.name))
+                       return sPorts[i].id;
        }
 
-       return portFound;
+       return B_NAME_NOT_FOUND;
 }
 
 
 status_t
-_get_port_info(port_id id, port_info *info, size_t size)
+_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))
@@ -775,42 +665,34 @@
        if (!sPortsActive || id < 0)
                return B_BAD_PORT_ID;
 
-       slot = id % sMaxPorts;
+       int32 slot = id % sMaxPorts;
 
-       state = disable_interrupts();
-       GRAB_PORT_LOCK(sPorts[slot]);
+       MutexLocker locker(sPorts[slot].lock);
 
        if (sPorts[slot].id != id || sPorts[slot].capacity == 0) {
-               RELEASE_PORT_LOCK(sPorts[slot]);
-               restore_interrupts(state);
                TRACE(("get_port_info: invalid port_id %ld\n", id));
                return B_BAD_PORT_ID;
        }
 
        // fill a port_info struct with info
        fill_port_info(&sPorts[slot], info, size);
-
-       RELEASE_PORT_LOCK(sPorts[slot]);
-       restore_interrupts(state);
-
        return B_OK;
 }
 
 
 status_t
-_get_next_port_info(team_id team, int32 *_cookie, struct port_info *info, 
size_t size)
+_get_next_port_info(team_id team, int32* _cookie, struct port_info* info,
+       size_t size)
 {
-       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)
+       if (info == NULL || size != sizeof(port_info) || _cookie == NULL
+               || team < B_OK)
                return B_BAD_VALUE;
        if (!sPortsActive)
                return B_BAD_PORT_ID;
 
-       slot = *_cookie;
+       int32 slot = *_cookie;
        if (slot >= sMaxPorts)
                return B_BAD_PORT_ID;
 
@@ -819,31 +701,25 @@
 
        info->port = -1; // used as found flag
 
-       // spinlock
-       state = disable_interrupts();
-       GRAB_PORT_LIST_LOCK();
-
        while (slot < sMaxPorts) {
-               GRAB_PORT_LOCK(sPorts[slot]);
-               if (sPorts[slot].id != -1 && sPorts[slot].capacity != 0 && 
sPorts[slot].owner == team) {
+               MutexLocker locker(sPorts[slot].lock);
+
+               if (sPorts[slot].id != -1 && !is_port_closed(slot)
+                       && sPorts[slot].owner == team) {
                        // found one!
                        fill_port_info(&sPorts[slot], info, size);
-
-                       RELEASE_PORT_LOCK(sPorts[slot]);
                        slot++;
                        break;
                }
-               RELEASE_PORT_LOCK(sPorts[slot]);

[... truncated: 605 lines follow ...]

Other related posts:

  • » [haiku-commits] r33728 - in haiku/trunk: headers/private/kernel src/system/kernel src/system/kernel/util - axeld