[haiku-commits] r33735 - in haiku/trunk: build/config_headers headers/private/kernel src/system/kernel

  • From: axeld@xxxxxxxxxxxxxxxx
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Fri, 23 Oct 2009 01:14:11 +0200 (CEST)

Author: axeld
Date: 2009-10-23 01:14:10 +0200 (Fri, 23 Oct 2009)
New Revision: 33735
Changeset: http://dev.haiku-os.org/changeset/33735/haiku

Modified:
   haiku/trunk/build/config_headers/tracing_config.h
   haiku/trunk/headers/private/kernel/heap.h
   haiku/trunk/src/system/kernel/heap.cpp
   haiku/trunk/src/system/kernel/port.cpp
Log:
* The alphabet is obviously hard, moved some tracing defines at their
  (hopefully) correct place.
* It seems to be even harder to understand basic locking primitives: when you
  think about it, it shouldn't surprise you that conditional variables never
  return B_WOULD_BLOCK. This fixes gdb again.
* Added tracing support to the ports subsystem.
* get_port_message() will now resize the port heap if needed (but will also
  take timeouts into account while doing so, more or less). The initial port
  space is 4MB (as before), the growth rate is the same, and the system wide
  limit is arbitrarily set to 64 MB (all swappable). A team limit has been set
  to 8 MB, but is not enforced yet. Since ports are using up address space in
  the kernel, those seems to be proper limits.
* This also fixes a strange, and rare lockup where the mouse cursor would still
  move, but everything else would basically hang, but look perfectly normal from
  KDL on the first look. As recently happened on Brecht's laptop, and debugged
  by mmlr and me: the cbuf space got used up when lots of windows wanted to
  redraw after a workspace switch. The app_server wouldn't answer anymore to
  client requests, but thought it would have done so, as LinkSender::Flush()
  doesn't care if it got a B_NO_MEMORY (the ports will now block until memory
  is available if possible, so that should not be a problem anymore).
* Improved "port" KDL command, it now also prints the messages in the port.


Modified: haiku/trunk/build/config_headers/tracing_config.h
===================================================================
--- haiku/trunk/build/config_headers/tracing_config.h   2009-10-22 22:09:20 UTC 
(rev 33734)
+++ haiku/trunk/build/config_headers/tracing_config.h   2009-10-22 23:14:10 UTC 
(rev 33735)
@@ -28,14 +28,15 @@
 #define BMESSAGE_TRACING                                               0
 #define KERNEL_HEAP_TRACING                                            0
 #define KTRACE_PRINTF_STACK_TRACE                              0       /* 
stack trace depth */
+#define OBJECT_CACHE_TRACING                                   0
+#define NET_BUFFER_TRACING                                             0
+#define NET_BUFFER_TRACING_STACK_TRACE                 0       /* stack trace 
depth */
 #define PAGE_ALLOCATION_TRACING                                        0
 #define PAGE_DAEMON_TRACING                                            0
 #define PAGE_WRITER_TRACING                                            0
 #define PARANOIA_TRACING                                               0
 #define PARANOIA_TRACING_STACK_TRACE                   0       /* stack trace 
depth */
-#define OBJECT_CACHE_TRACING                                   0
-#define NET_BUFFER_TRACING                                             0
-#define NET_BUFFER_TRACING_STACK_TRACE                 0       /* stack trace 
depth */
+#define PORT_TRACING                                                   0
 #define RUNTIME_LOADER_TRACING                                 0
 #define SCHEDULER_TRACING                                              0
 #define SCHEDULING_ANALYSIS_TRACING                            0

Modified: haiku/trunk/headers/private/kernel/heap.h
===================================================================
--- haiku/trunk/headers/private/kernel/heap.h   2009-10-22 22:09:20 UTC (rev 
33734)
+++ haiku/trunk/headers/private/kernel/heap.h   2009-10-22 23:14:10 UTC (rev 
33735)
@@ -43,10 +43,10 @@
 
 // malloc- and memalign_nogrow disallow waiting for a grow to happen - only to
 // be used by vm functions that may deadlock on a triggered area creation.
-void *memalign_nogrow(size_t alignment, size_t size);
-void *malloc_nogrow(size_t size);
+void* memalign_nogrow(size_t alignment, size_t size);
+void* malloc_nogrow(size_t size);
 
-void *memalign(size_t alignment, size_t size);
+void* memalign(size_t alignment, size_t size);
 
 void deferred_free(void* block);
 
@@ -54,6 +54,8 @@
 void* malloc_referenced_acquire(void* data);
 void malloc_referenced_release(void* data);
 
+void heap_add_area(heap_allocator* heap, area_id areaID, addr_t base,
+       size_t size);
 heap_allocator*        heap_create_allocator(const char* name, addr_t base,
        size_t size, const heap_class* heapClass, bool allocateOnHeap);
 void* heap_memalign(heap_allocator* heap, size_t alignment, size_t size);

Modified: haiku/trunk/src/system/kernel/heap.cpp
===================================================================
--- haiku/trunk/src/system/kernel/heap.cpp      2009-10-22 22:09:20 UTC (rev 
33734)
+++ haiku/trunk/src/system/kernel/heap.cpp      2009-10-22 23:14:10 UTC (rev 
33735)
@@ -973,7 +973,7 @@
 // #pragma mark - Heap functions
 
 
-static void
+void
 heap_add_area(heap_allocator *heap, area_id areaID, addr_t base, size_t size)
 {
        heap_area *area = (heap_area *)base;

Modified: haiku/trunk/src/system/kernel/port.cpp
===================================================================
--- haiku/trunk/src/system/kernel/port.cpp      2009-10-22 22:09:20 UTC (rev 
33734)
+++ haiku/trunk/src/system/kernel/port.cpp      2009-10-22 23:14:10 UTC (rev 
33735)
@@ -6,8 +6,10 @@
  * Distributed under the terms of the NewOS License.
  */
 
+
 /*!    Ports for IPC */
 
+
 #include <port.h>
 
 #include <ctype.h>
@@ -24,6 +26,7 @@
 #include <sem.h>
 #include <syscall_restart.h>
 #include <team.h>
+#include <tracing.h>
 #include <util/AutoLock.h>
 #include <util/list.h>
 #include <wait_for_objects.h>
@@ -70,7 +73,181 @@
                        void                    Notify(uint32 opcode, port_id 
team);
 };
 
+
+#if PORT_TRACING
+namespace PortTracing {
+
+class Create : public AbstractTraceEntry {
+public:
+       Create(port_entry& port)
+               :
+               fID(port.id),
+               fOwner(port.owner),
+               fCapacity(port.capacity)
+       {
+               fName = alloc_tracing_buffer_strcpy(port.lock.name, 
B_OS_NAME_LENGTH,
+                       false);
+
+               Initialized();
+       }
+
+       virtual void AddDump(TraceOutput& out)
+       {
+               out.Print("port %ld created, name \"%s\", owner %ld, capacity 
%ld",
+                       fID, fName, fOwner, fCapacity);
+       }
+
+private:
+       port_id                         fID;
+       char*                           fName;
+       team_id                         fOwner;
+       int32                           fCapacity;
+};
+
+
+class Delete : public AbstractTraceEntry {
+public:
+       Delete(port_entry& port)
+               :
+               fID(port.id)
+       {
+               Initialized();
+       }
+
+       virtual void AddDump(TraceOutput& out)
+       {
+               out.Print("port %ld deleted", fID);
+       }
+
+private:
+       port_id                         fID;
+};
+
+
+class Read : public AbstractTraceEntry {
+public:
+       Read(port_entry& port, int32 code, ssize_t result)
+               :
+               fID(port.id),
+               fReadCount(port.read_count),
+               fWriteCount(port.write_count),
+               fCode(code),
+               fResult(result)
+       {
+               Initialized();
+       }
+
+       virtual void AddDump(TraceOutput& out)
+       {
+               out.Print("port %ld read, read %ld, write %ld, code %lx: %ld",
+                       fID, fReadCount, fWriteCount, fCode, fResult);
+       }
+
+private:
+       port_id                         fID;
+       int32                           fReadCount;
+       int32                           fWriteCount;
+       int32                           fCode;
+       ssize_t                         fResult;
+};
+
+
+class Write : public AbstractTraceEntry {
+public:
+       Write(port_entry& port, int32 code, size_t bufferSize, ssize_t result)
+               :
+               fID(port.id),
+               fReadCount(port.read_count),
+               fWriteCount(port.write_count),
+               fCode(code),
+               fBufferSize(bufferSize),
+               fResult(result)
+       {
+               Initialized();
+       }
+
+       virtual void AddDump(TraceOutput& out)
+       {
+               out.Print("port %ld write, read %ld, write %ld, code %lx, size 
%ld: %ld",
+                       fID, fReadCount, fWriteCount, fCode, fBufferSize, 
fResult);
+       }
+
+private:
+       port_id                         fID;
+       int32                           fReadCount;
+       int32                           fWriteCount;
+       int32                           fCode;
+       size_t                          fBufferSize;
+       ssize_t                         fResult;
+};
+
+
+class Info : public AbstractTraceEntry {
+public:
+       Info(port_entry& port, int32 code, ssize_t result)
+               :
+               fID(port.id),
+               fReadCount(port.read_count),
+               fWriteCount(port.write_count),
+               fCode(code),
+               fResult(result)
+       {
+               Initialized();
+       }
+
+       virtual void AddDump(TraceOutput& out)
+       {
+               out.Print("port %ld info, read %ld, write %ld, code %lx: %ld",
+                       fID, fReadCount, fWriteCount, fCode, fResult);
+       }
+
+private:
+       port_id                         fID;
+       int32                           fReadCount;
+       int32                           fWriteCount;
+       int32                           fCode;
+       ssize_t                         fResult;
+};
+
+
+class OwnerChange : public AbstractTraceEntry {
+public:
+       OwnerChange(port_entry& port, team_id newOwner, status_t status)
+               :
+               fID(port.id),
+               fOldOwner(port.owner),
+               fNewOwner(newOwner),
+               fStatus(status)
+       {
+               Initialized();
+       }
+
+       virtual void AddDump(TraceOutput& out)
+       {
+               out.Print("port %ld owner change from %ld to %ld: %s", fID, 
fOldOwner,
+                       fNewOwner, strerror(fStatus));
+       }
+
+private:
+       port_id                         fID;
+       team_id                         fOldOwner;
+       team_id                         fNewOwner;
+       status_t                        fStatus;
+};
+
+}      // namespace PortTracing
+
+#      define T(x) new(std::nothrow) PortTracing::x;
+#else
+#      define T(x) ;
+#endif
+
+
 static const size_t kInitialPortBufferSize = 4 * 1024 * 1024;
+static const size_t kTotalSpaceLimit = 64 * 1024 * 1024;
+static const size_t kTeamSpaceLimit = 8 * 1024 * 1024;
+static const size_t kBufferGrowRate = kInitialPortBufferSize;
+
 #define MAX_QUEUE_LENGTH 4096
 #define PORT_MAX_MESSAGE_SIZE (256 * 1024)
 
@@ -81,6 +258,10 @@
 static struct port_entry* sPorts;
 static area_id sPortArea;
 static heap_allocator* sPortAllocator;
+static ConditionVariable sNoSpaceCondition;
+static vint32 sTotalSpaceInUse;
+static vint32 sAreaChangeCounter;
+static vint32 sAllocatingArea;
 static bool sPortsActive = false;
 static port_id sNextPort = 1;
 static int32 sFirstFreeSlot = 1;
@@ -161,6 +342,15 @@
        kprintf(" write_count:     %ld\n", port->write_count);
        kprintf(" total count:     %ld\n", port->total_count);
 
+       if (!port->messages.IsEmpty()) {
+               kprintf("messages:\n");
+
+               MessageList::Iterator iterator = port->messages.GetIterator();
+               while (port_message* message = iterator.Next()) {
+                       kprintf(" %p  %08lx  %ld\n", message, message->code, 
message->size);
+               }
+       }
+
        set_debug_variable("_port", (addr_t)port);
        set_debug_variable("_portID", port->id);
        set_debug_variable("_owner", port->owner);
@@ -170,9 +360,8 @@
 static int
 dump_port_info(int argc, char** argv)
 {
+       ConditionVariable* condition = NULL;
        const char* name = NULL;
-       ConditionVariable* condition = NULL;
-       int i;
 
        if (argc < 2) {
                print_debugger_command_usage(argv[0]);
@@ -181,17 +370,17 @@
 
        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*)parse_expression(argv[2]));
                        return 0;
                } else if (!strcmp(argv[1], "condition"))
-                       condition = (ConditionVariable*)strtoul(argv[2], NULL, 
0);
+                       condition = 
(ConditionVariable*)parse_expression(argv[2]);
                else if (!strcmp(argv[1], "name"))
                        name = argv[2];
-       } else if (isdigit(argv[1][0])) {
+       } else if (parse_expression(argv[1]) > 0) {
                // if the argument looks like a number, treat it as such
-               uint32 num = strtoul(argv[1], NULL, 0);
-               uint32 slot = num % sMaxPorts;
-               if (sPorts[slot].id != (int)num) {
+               int32 num = parse_expression(argv[1]);
+               int32 slot = num % sMaxPorts;
+               if (sPorts[slot].id != num) {
                        kprintf("port %ld (%#lx) doesn't exist!\n", num, num);
                        return 0;
                }
@@ -201,7 +390,7 @@
                name = argv[1];
 
        // walk through the ports list, trying to match name
-       for (i = 0; i < sMaxPorts; i++) {
+       for (int32 i = 0; i < sMaxPorts; i++) {
                if ((name != NULL && sPorts[i].lock.name != NULL
                                && !strcmp(name, sPorts[i].lock.name))
                        || (condition != NULL && (&sPorts[i].read_condition == 
condition
@@ -226,24 +415,97 @@
 static void
 put_port_message(port_message* message)
 {
+       size_t size = sizeof(port_message) + message->size;
        heap_free(sPortAllocator, message);
+
+       atomic_add(&sTotalSpaceInUse, -size);
+       sNoSpaceCondition.NotifyAll();
 }
 
 
-static port_message*
-get_port_message(int32 code, size_t bufferSize)
+static status_t
+get_port_message(int32 code, size_t bufferSize, uint32 flags, bigtime_t 
timeout,
+       port_message** _message)
 {
-       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;
-       }
+       size_t size = sizeof(port_message) + bufferSize;
+       bool limitReached = false;
 
-       message->code = code;
-       message->size = bufferSize;
+       while (true) {
+               if (atomic_add(&sTotalSpaceInUse, size)
+                               > int32(kTotalSpaceLimit - size)) {
+                       // TODO: add per team limit
+                       // We are not allowed to create another heap area, as 
our
+                       // space limit has been reached - just wait until we get
+                       // some free space again.
+                       limitReached = true;
 
-       return message;
+               wait:
+                       MutexLocker locker(sPortsLock);
+
+                       atomic_add(&sTotalSpaceInUse, -size);
+
+                       // TODO: we don't want to wait - but does that also 
mean we
+                       // shouldn't wait for the area creation?
+                       if (limitReached && (flags & B_RELATIVE_TIMEOUT) != 0
+                               && timeout <= 0)
+                               return B_WOULD_BLOCK;
+
+                       ConditionVariableEntry entry;
+                       sNoSpaceCondition.Add(&entry);
+
+                       locker.Unlock();
+
+                       status_t status = entry.Wait(flags, timeout);
+                       if (status == B_TIMED_OUT)
+                               return B_TIMED_OUT;
+
+                       // just try again
+                       limitReached = false;
+                       continue;
+               }
+
+               int32 areaChangeCounter = atomic_get(&sAreaChangeCounter);
+
+               // Quota is fulfilled, try to allocate the buffer
+
+               port_message* message
+                       = (port_message*)heap_memalign(sPortAllocator, 0, size);
+               if (message != NULL) {
+                       message->code = code;
+                       message->size = bufferSize;
+
+                       *_message = message;
+                       return B_OK;
+               }
+
+               if (atomic_or(&sAllocatingArea, 1) != 0) {
+                       // Just wait for someone else to create an area for us
+                       goto wait;
+               }
+
+               if (areaChangeCounter != atomic_get(&sAreaChangeCounter)) {
+                       atomic_add(&sTotalSpaceInUse, -size);
+                       continue;
+               }
+
+               // Create a new area for the heap to use
+
+               addr_t base;
+               area_id area = create_area("port grown buffer", (void**)&base,
+                       B_ANY_KERNEL_ADDRESS, kBufferGrowRate, B_NO_LOCK,
+                       B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
+               if (area < 0) {
+                       // it's time to let the userland feel our pain
+                       sNoSpaceCondition.NotifyAll();
+                       return B_NO_MEMORY;
+               }
+
+               heap_add_area(sPortAllocator, area, base, kBufferGrowRate);
+
+               atomic_add(&sAreaChangeCounter, 1);
+               sNoSpaceCondition.NotifyAll();
+               atomic_and(&sAllocatingArea, 0);
+       }
 }
 
 
@@ -385,7 +647,13 @@
                sizeof(port_message), 8, 4, 64};
        sPortAllocator = heap_create_allocator("port buffer", base,
                kInitialPortBufferSize, &kBufferHeapClass, true);
+       if (sPortAllocator == NULL) {
+               panic("unable to create port heap");
+               return B_NO_MEMORY;
+       }
 
+       sNoSpaceCondition.Init(sPorts, "port space");
+
        // add debugger commands
        add_debugger_command_etc("ports", &dump_port_list,
                "Dump a list of all active ports (for team, with name, etc.)",
@@ -396,12 +664,12 @@
                "  <name>             - Part of the name of the ports.\n", 0);
        add_debugger_command_etc("port", &dump_port_info,
                "Dump info about a particular port",
-               "([ \"address\" ] <address>) | ([ \"name\" ] <name>) "
-                       "| (\"sem\" <sem>)\n"
+               "(<id> | [ \"address\" ] <address>) | ([ \"name\" ] <name>) "
+                       "| (\"condition\" <address>)\n"
                "Prints info about the specified port.\n"
-               "  <address>  - Pointer to the port structure.\n"
-               "  <name>     - Name of the port.\n"
-               "  <sem>      - ID of the port's read or write semaphore.\n", 
0);
+               "  <address>   - Pointer to the port structure.\n"
+               "  <name>      - Name of the port.\n"
+               "  <condition> - address of the port's read or write 
condition.\n", 0);
 
        new(&sNotificationService) PortNotificationService();
        sPortsActive = true;
@@ -463,6 +731,8 @@
                        sPorts[i].select_infos = NULL;
 
                        port_id id = sPorts[i].id;
+
+                       T(Create(sPorts[i]));
                        portLocker.Unlock();
 
                        TRACE(("create_port() done: port created %ld\n", id));
@@ -528,6 +798,8 @@
                return B_BAD_PORT_ID;
        }
 
+       T(Delete(sPorts[slot]));
+
        // mark port as invalid
        sPorts[slot].id = -1;
        free((char*)sPorts[slot].lock.name);
@@ -748,12 +1020,15 @@
        if (!sPortsActive || id < 0)
                return B_BAD_PORT_ID;
 
+       flags &= B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT | B_RELATIVE_TIMEOUT
+               | B_ABSOLUTE_TIMEOUT;
        int32 slot = id % sMaxPorts;
 
        MutexLocker locker(sPorts[slot].lock);
 
        if (sPorts[slot].id != id
                || (is_port_closed(slot) && sPorts[slot].messages.IsEmpty())) {
+               T(Info(sPorts[slot], 0, B_BAD_PORT_ID));
                TRACE(("port_buffer_size_etc(): %s port %ld\n",
                        sPorts[slot].id == id ? "closed" : "invalid", id));
                return B_BAD_PORT_ID;
@@ -761,6 +1036,9 @@
 
        if (sPorts[slot].read_count <= 0) {
                // We need to wait for a message to appear
+               if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0)
+                       return B_WOULD_BLOCK;
+
                ConditionVariableEntry entry;
                sPorts[slot].read_condition.Add(&entry);
 
@@ -768,10 +1046,13 @@
 
                // block if no message, or, if B_TIMEOUT flag set, block with 
timeout
                status_t status = entry.Wait(flags, timeout);
-               if (status != B_OK)
+               if (status == B_OK && entry.WaitStatus() != B_OK)
+                       status = entry.WaitStatus();
+
+               if (status != B_OK) {
+                       T(Info(sPorts[slot], 0, status));
                        return status;
-               if (entry.WaitStatus() != B_OK)
-                       return entry.WaitStatus();
+               }
 
                locker.Lock();
        }
@@ -793,6 +1074,8 @@
        info->sender_group = message->sender_group;
        info->sender_team = message->sender_team;
 
+       T(Info(sPorts[slot], message->code, B_OK));
+
        // notify next one, as we haven't read from the port
        sPorts[slot].read_condition.NotifyOne();
 
@@ -854,12 +1137,18 @@
 
        if (sPorts[slot].id != id
                || (is_port_closed(slot) && sPorts[slot].messages.IsEmpty())) {
+               T(Read(sPorts[slot], 0, B_BAD_PORT_ID));
                TRACE(("read_port_etc(): %s port %ld\n",
                        sPorts[slot].id == id ? "closed" : "invalid", id));
                return B_BAD_PORT_ID;
        }
 
-       if (sPorts[slot].read_count-- <= 0) {
+       if (sPorts[slot].read_count <= 0) {
+               if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0)
+                       return B_WOULD_BLOCK;
+
+               sPorts[slot].read_count--;
+
                // We need to wait for a message to appear
                ConditionVariableEntry entry;
                sPorts[slot].read_condition.Add(&entry);
@@ -873,14 +1162,18 @@
 
                if (sPorts[slot].id != id) {
                        // the port is no longer there
+                       T(Read(sPorts[slot], 0, B_BAD_PORT_ID));
                        return B_BAD_PORT_ID;
                }
 
                if (status != B_OK || entry.WaitStatus() != B_OK) {
+                       T(Read(sPorts[slot], 0,
+                               status != B_OK ? status : entry.WaitStatus()));
                        sPorts[slot].read_count++;
                        return status != B_OK ? status : entry.WaitStatus();
                }
-       }
+       } else
+               sPorts[slot].read_count--;
 
        // determine tail & get the length of the message
        port_message* message = sPorts[slot].messages.Head();
@@ -893,6 +1186,8 @@
                size_t size = copy_port_message(message, _code, buffer, 
bufferSize,
                        userCopy);
 
+               T(Read(sPorts[slot], message->code, size));
+
                sPorts[slot].read_count++;
                sPorts[slot].read_condition.NotifyOne();
                        // we only peeked, but didn't grab the message
@@ -911,6 +1206,7 @@
 
        size_t size = copy_port_message(message, _code, buffer, bufferSize,
                userCopy);
+       T(Read(sPorts[slot], message->code, size));
 
        put_port_message(message);
        return size;
@@ -948,9 +1244,18 @@
        // mask irrelevant flags (for acquire_sem() usage)
        flags &= B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT | B_RELATIVE_TIMEOUT
                | B_ABSOLUTE_TIMEOUT;
+       if ((flags & B_RELATIVE_TIMEOUT) != 0
+               && timeout != B_INFINITE_TIMEOUT && timeout > 0) {
+               // Make the timeout absolute, since we have more than one step 
where
+               // we might have to wait
+               flags = (flags & ~B_RELATIVE_TIMEOUT) | B_ABSOLUTE_TIMEOUT;
+               timeout += system_time();
+       }
+
        bool userCopy = (flags & PORT_FLAG_USE_USER_MEMCPY) > 0;
 
        int32 slot = id % sMaxPorts;
+       status_t status;
 
        MutexLocker locker(sPorts[slot].lock);
 
@@ -963,35 +1268,41 @@
                return B_BAD_PORT_ID;
        }
 
-       if (sPorts[slot].write_count-- <= 0) {
+       if (sPorts[slot].write_count <= 0) {
+               if ((flags & B_RELATIVE_TIMEOUT) != 0 && timeout <= 0)
+                       return B_WOULD_BLOCK;
+
+               sPorts[slot].write_count--;
+
                // We need to block in order to wait for a free message slot
                ConditionVariableEntry entry;
                sPorts[slot].write_condition.Add(&entry);
 
                locker.Unlock();
 
-               status_t status = entry.Wait(flags, timeout);
+               status = entry.Wait(flags, timeout);
 
                locker.Lock();
 
                if (sPorts[slot].id != id) {
                        // the port is no longer there
+                       T(Write(sPorts[slot], 0, 0, B_BAD_PORT_ID));
                        return B_BAD_PORT_ID;
                }
 
                if (status != B_OK || entry.WaitStatus() != B_OK) {
-                       sPorts[slot].write_count++;
-                       return status != B_OK ? status : entry.WaitStatus();
+                       if (status == B_OK)
+                               status = entry.WaitStatus();
+                       goto error;
                }
-       }
+       } else
+               sPorts[slot].write_count--;
 
-       port_message* message = get_port_message(msgCode, bufferSize);
-       if (message == NULL) {
-               // Give up our slot in the queue again, and let someone else
-               // try and fail
-               sPorts[slot].write_condition.NotifyOne();
-               return B_NO_MEMORY;
-       }
+       port_message* message;
+       status = get_port_message(msgCode, bufferSize, flags, timeout,
+               &message);
+       if (status != B_OK)
+               goto error;
 
        // sender credentials
        message->sender = geteuid();
@@ -1011,7 +1322,7 @@
                                        msgVecs[i].iov_base, bytes);
                                if (status != B_OK) {
                                        put_port_message(message);
-                                       return status;
+                                       goto error;
                                }
 
                                bufferSize -= bytes;
@@ -1037,10 +1348,21 @@
        sPorts[slot].messages.Add(message);
        sPorts[slot].read_count++;
 
+       T(Write(sPorts[slot], message->code, message->size, B_OK));
+
        notify_port_select_events(slot, B_EVENT_READ);
        sPorts[slot].read_condition.NotifyOne();
+       return B_OK;
 
-       return B_OK;
+error:
+       // Give up our slot in the queue again, and let someone else
+       // try and fail
+       T(Write(sPorts[slot], 0, 0, status));
+       sPorts[slot].write_count++;
+       notify_port_select_events(slot, B_EVENT_WRITE);
+       sPorts[slot].write_condition.NotifyOne();
+
+       return status;
 }
 
 
@@ -1060,9 +1382,13 @@
                TRACE(("set_port_owner: invalid port_id %ld\n", id));
                return B_BAD_PORT_ID;
        }
-       if (!team_is_valid(team))
+       if (!team_is_valid(team)) {
+               T(OwnerChange(sPorts[slot], team, B_BAD_TEAM_ID));
                return B_BAD_TEAM_ID;
+       }
 
+       T(OwnerChange(sPorts[slot], team, B_OK));
+
        // transfer ownership to other team
        sPorts[slot].owner = team;
 


Other related posts: