diff --git a/headers/private/kernel/cbuf.h b/headers/private/kernel/cbuf.h deleted file mode 100644 index 5e48fc0ec4..0000000000 --- a/headers/private/kernel/cbuf.h +++ /dev/null @@ -1,50 +0,0 @@ -/* -** Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. -** Distributed under the terms of the NewOS License. -*/ -#ifndef _KERNEL_CBUF_H -#define _KERNEL_CBUF_H - - -#include - - -typedef struct cbuf cbuf; - - -#ifdef __cplusplus -extern "C" { -#endif - -status_t cbuf_init(void); -cbuf *cbuf_get_chain(size_t len); -cbuf *cbuf_get_chain_noblock(size_t len); -void cbuf_free_chain_noblock(cbuf *buf); -void cbuf_free_chain(cbuf *buf); - -size_t cbuf_get_length(cbuf *buf); -void *cbuf_get_ptr(cbuf *buf, size_t offset); -bool cbuf_is_contig_region(cbuf *buf, size_t start, size_t end); - -status_t cbuf_memcpy_to_chain(cbuf *chain, size_t offset, const void *_src, size_t len); -status_t cbuf_memcpy_from_chain(void *dest, cbuf *chain, size_t offset, size_t len); - -status_t cbuf_user_memcpy_to_chain(cbuf *chain, size_t offset, const void *_src, size_t len); -status_t cbuf_user_memcpy_from_chain(void *dest, cbuf *chain, size_t offset, size_t len); - -uint16 cbuf_ones_cksum16(cbuf *chain, size_t offset, size_t len); - -cbuf *cbuf_merge_chains(cbuf *chain1, cbuf *chain2); -cbuf *cbuf_duplicate_chain(cbuf *chain, size_t offset, size_t len); - -status_t cbuf_truncate_head(cbuf *chain, size_t trunc_bytes); -status_t cbuf_truncate_tail(cbuf *chain, size_t trunc_bytes); - -void cbuf_test(void); - // ToDo: to be removed... - -#ifdef __cplusplus -} -#endif - -#endif /* _KERNEL_CBUF_H */ diff --git a/src/system/kernel/main.cpp b/src/system/kernel/main.cpp index 47be6177bf..84c7fe3f65 100644 --- a/src/system/kernel/main.cpp +++ b/src/system/kernel/main.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2002-2009, Axel Dörfler, axeld@pinc-software.de. * Distributed under the terms of the MIT License. * * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. @@ -18,7 +18,6 @@ #include #include #include -#include #include #include #include @@ -163,21 +162,13 @@ _start(kernel_args *bootKernelArgs, int currentCPU) 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 @@ _start(kernel_args *bootKernelArgs, int currentCPU) 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 @@ main2(void *unused) 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(); diff --git a/src/system/kernel/port.cpp b/src/system/kernel/port.cpp index fc39248446..3027b3976f 100644 --- a/src/system/kernel/port.cpp +++ b/src/system/kernel/port.cpp @@ -18,7 +18,7 @@ #include #include -#include +#include #include #include #include @@ -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 { + int32 code; + size_t size; + uid_t sender; + gid_t sender_group; + team_id sender_team; + char buffer[0]; +}; + +typedef DoublyLinkedList 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 @@ public: 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 @@ public: 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 @@ PortNotificationService::Notify(uint32 opcode, port_id port) 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 @@ dump_port_list(int argc, char **argv) } 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 @@ dump_port_info(int argc, char **argv) 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 @@ dump_port_info(int argc, char **argv) // 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 @@ notify_port_select_events(int slot, uint16 events) 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,22 +260,44 @@ is_port_closed(int32 slot) 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; } @@ -307,38 +310,28 @@ fill_port_info(struct port_entry *port, port_info *info, size_t size) 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,23 +354,37 @@ status_t 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, @@ -406,71 +413,36 @@ port_init(kernel_args *args) 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; - } - - // 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(); + sUsedPorts++; // 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 @@ create_port(int32 queueLength, const char *name) 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 @@ create_port(int32 queueLength, const char *name) } } - // 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 @@ close_port(port_id id) // 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); - - delete_sem(readSem); - delete_sem(writeSem); - - return B_NO_ERROR; -} - - -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; - - state = disable_interrupts(); - GRAB_PORT_LOCK(sPorts[slot]); - - 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 */ - 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); - - notify_port_select_events(slot, B_EVENT_INVALID); - sPorts[slot].select_infos = NULL; - - 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); - - // 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); + sPorts[slot].read_condition.NotifyAll(false, B_BAD_PORT_ID); + sPorts[slot].write_condition.NotifyAll(false, B_BAD_PORT_ID); return B_OK; } status_t -select_port(int32 id, struct select_info *info, bool kernel) +delete_port(port_id id) { - cpu_status state; - int32 slot; - status_t error = B_OK; + TRACE(("delete_port(id = %ld)\n", id)); - if (id < 0) + 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 || is_port_closed(slot)) { - // bad port ID - error = B_BAD_SEM_ID; - } else 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; - - if (info->selected_events != 0) { - uint16 events = 0; - int32 writeCount = 0; - - info->next = sPorts[slot].select_infos; - sPorts[slot].select_infos = info; - - // check for events - if ((info->selected_events & B_EVENT_READ) != 0 - && !list_is_empty(&sPorts[slot].msg_queue)) { - events |= B_EVENT_READ; - } - - 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); - } + if (sPorts[slot].id != id) { + TRACE(("delete_port: invalid port_id %ld\n", id)); + return B_BAD_PORT_ID; } - RELEASE_PORT_LOCK(sPorts[slot]); - restore_interrupts(state); + // mark port as invalid + sPorts[slot].id = -1; + free((char*)sPorts[slot].lock.name); + sPorts[slot].lock.name = NULL; - return error; + 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 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 + if (slot < sFirstFreeSlot) + sFirstFreeSlot = slot; + + sUsedPorts--; + return B_OK; } status_t -deselect_port(int32 id, struct select_info *info, bool kernel) +select_port(int32 id, struct select_info* info, bool kernel) { - cpu_status state; - int32 slot; - if (id < 0) return B_BAD_PORT_ID; + int32 slot = id % sMaxPorts; + + MutexLocker locker(sPorts[slot].lock); + + 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 + return B_NOT_ALLOWED; + } + + info->selected_events &= B_EVENT_READ | B_EVENT_WRITE | B_EVENT_INVALID; + + if (info->selected_events != 0) { + uint16 events = 0; + + info->next = sPorts[slot].select_infos; + sPorts[slot].select_infos = info; + + // check for events + if ((info->selected_events & B_EVENT_READ) != 0 + && !sPorts[slot].messages.IsEmpty()) { + events |= B_EVENT_READ; + } + + if (sPorts[slot].write_count > 0) + events |= B_EVENT_WRITE; + + if (events != 0) + notify_select_events(info, events); + } + + return B_OK; +} + + +status_t +deselect_port(int32 id, struct select_info* info, bool kernel) +{ + 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 @@ deselect_port(int32 id, struct select_info *info, bool kernel) *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 @@ find_port(const char *name) // 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 @@ _get_port_info(port_id id, port_info *info, size_t size) 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 @@ _get_next_port_info(team_id team, int32 *_cookie, struct port_info *info, size_t 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]); + slot++; } - RELEASE_PORT_LIST_LOCK(); - restore_interrupts(state); if (info->port == -1) return B_BAD_PORT_ID; *_cookie = slot; - return B_NO_ERROR; + return B_OK; } @@ -862,122 +738,87 @@ port_buffer_size_etc(port_id id, uint32 flags, bigtime_t timeout) return error != B_OK ? error : info.size; } + status_t -_get_port_message_info_etc(port_id id, port_message_info *info, +_get_port_message_info_etc(port_id id, port_message_info* info, size_t infoSize, uint32 flags, bigtime_t timeout) { if (info == NULL || infoSize != sizeof(port_message_info)) return B_BAD_VALUE; - - cpu_status state; - sem_id cachedSem; - status_t status; - port_msg *msg; - int32 slot; - 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 - || (is_port_closed(slot) && list_is_empty(&sPorts[slot].msg_queue))) { - RELEASE_PORT_LOCK(sPorts[slot]); - restore_interrupts(state); + || (is_port_closed(slot) && sPorts[slot].messages.IsEmpty())) { TRACE(("port_buffer_size_etc(): %s port %ld\n", sPorts[slot].id == id ? "closed" : "invalid", id)); return B_BAD_PORT_ID; } - cachedSem = sPorts[slot].read_sem; + if (sPorts[slot].read_count <= 0) { + // We need to wait for a message to appear + ConditionVariableEntry entry; + sPorts[slot].read_condition.Add(&entry); - RELEASE_PORT_LOCK(sPorts[slot]); - restore_interrupts(state); + locker.Unlock(); - // 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_t status = entry.Wait(flags, timeout); + if (status != B_OK) + return status; + if (entry.WaitStatus() != B_OK) + return entry.WaitStatus(); - status = acquire_sem_etc(cachedSem, 1, flags, timeout); - if (status != B_OK && status != B_BAD_SEM_ID) - 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(); - GRAB_PORT_LOCK(sPorts[slot]); + locker.Lock(); + } if (sPorts[slot].id != id) { // the port is no longer there - RELEASE_PORT_LOCK(sPorts[slot]); - restore_interrupts(state); return B_BAD_PORT_ID; } // determine tail & get the length of the message - status_t error = B_OK; - msg = (port_msg*)list_get_first_item(&sPorts[slot].msg_queue); - if (msg == NULL) { - if (status == B_OK) - panic("port %ld: no messages found\n", sPorts[slot].id); - - error = B_BAD_PORT_ID; - } else { - info->size = msg->size; - info->sender = msg->sender; - info->sender_group = msg->sender_group; - info->sender_team = msg->sender_team; + port_message* message = sPorts[slot].messages.Head(); + if (message == NULL) { + panic("port %ld: no messages found\n", sPorts[slot].id); + return B_ERROR; } - RELEASE_PORT_LOCK(sPorts[slot]); - restore_interrupts(state); + info->size = message->size; + info->sender = message->sender; + info->sender_group = message->sender_group; + info->sender_team = message->sender_team; - // restore read_sem, as we haven't read from the port - release_sem(cachedSem); + // notify next one, as we haven't read from the port + sPorts[slot].read_condition.NotifyOne(); - // return length of item at end of queue - return error; + return B_OK; } ssize_t port_count(port_id id) { - cpu_status state; - int32 count = 0; - int32 slot; - 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(("port_count: invalid port_id %ld\n", id)); return B_BAD_PORT_ID; } - if (get_sem_count(sPorts[slot].read_sem, &count) == B_OK) { - // do not return negative numbers - if (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]); - restore_interrupts(state); + int32 count = sPorts[slot].read_count; + // do not return negative numbers + if (count < 0) + count = 0; // return count of messages return count; @@ -985,224 +826,177 @@ port_count(port_id id) ssize_t -read_port(port_id port, int32 *msgCode, void *msgBuffer, size_t bufferSize) +read_port(port_id port, int32* msgCode, void* buffer, size_t bufferSize) { - return read_port_etc(port, msgCode, msgBuffer, bufferSize, 0, 0); + return read_port_etc(port, msgCode, buffer, bufferSize, 0, 0); } ssize_t -read_port_etc(port_id id, int32 *_msgCode, void *msgBuffer, size_t bufferSize, +read_port_etc(port_id id, int32* _code, void* buffer, size_t bufferSize, uint32 flags, bigtime_t timeout) { - cpu_status state; - sem_id cachedSem; - status_t status; - bool userCopy = (flags & PORT_FLAG_USE_USER_MEMCPY) != 0; - bool peekOnly = !userCopy && (flags & B_PEEK_PORT_MESSAGE) != 0; - port_msg *msg; - size_t size; - int slot; - if (!sPortsActive || id < 0) return B_BAD_PORT_ID; - - if ((msgBuffer == NULL && bufferSize > 0) - || timeout < 0) + if ((buffer == NULL && bufferSize > 0) || timeout < 0) return B_BAD_VALUE; - flags = flags & (B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT - | B_RELATIVE_TIMEOUT | B_ABSOLUTE_TIMEOUT); - slot = id % sMaxPorts; + bool userCopy = (flags & PORT_FLAG_USE_USER_MEMCPY) != 0; + bool peekOnly = !userCopy && (flags & B_PEEK_PORT_MESSAGE) != 0; + // TODO: we could allow peeking for user apps now - state = disable_interrupts(); - GRAB_PORT_LOCK(sPorts[slot]); + 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) && list_is_empty(&sPorts[slot].msg_queue))) { - RELEASE_PORT_LOCK(sPorts[slot]); - restore_interrupts(state); + || (is_port_closed(slot) && sPorts[slot].messages.IsEmpty())) { TRACE(("read_port_etc(): %s port %ld\n", sPorts[slot].id == id ? "closed" : "invalid", id)); return B_BAD_PORT_ID; } - // store sem_id in local variable - cachedSem = sPorts[slot].read_sem; - // unlock port && enable ints/ - RELEASE_PORT_LOCK(sPorts[slot]); - restore_interrupts(state); + if (sPorts[slot].read_count-- <= 0) { + // We need to wait for a message to appear + ConditionVariableEntry entry; + sPorts[slot].read_condition.Add(&entry); - status = acquire_sem_etc(cachedSem, 1, flags, timeout); - // get 1 entry from the queue, block if needed + locker.Unlock(); - if (status != B_OK && status != B_BAD_SEM_ID) - return status; + // block if no message, or, if B_TIMEOUT flag set, block with timeout + status_t status = entry.Wait(flags, timeout); - // 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 + locker.Lock(); - state = disable_interrupts(); - GRAB_PORT_LOCK(sPorts[slot]); + if (sPorts[slot].id != id) { + // the port is no longer there + return B_BAD_PORT_ID; + } - // first, let's check if the port is still alive - if (sPorts[slot].id == -1) { - // the port has been deleted in the meantime - RELEASE_PORT_LOCK(sPorts[slot]); - restore_interrupts(state); - return B_BAD_PORT_ID; + if (status != B_OK || entry.WaitStatus() != B_OK) { + sPorts[slot].read_count++; + return status != B_OK ? status : entry.WaitStatus(); + } } - msg = (port_msg*)list_get_first_item(&sPorts[slot].msg_queue); - if (msg == NULL) { - 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; + // determine tail & get the length of the message + port_message* message = sPorts[slot].messages.Head(); + if (message == NULL) { + panic("port %ld: no messages found\n", sPorts[slot].id); + return B_ERROR; } if (peekOnly) { - size = min_c(bufferSize, msg->size); - if (_msgCode != NULL) - *_msgCode = msg->code; - if (size > 0) - cbuf_memcpy_from_chain(msgBuffer, msg->buffer_chain, 0, size); - RELEASE_PORT_LOCK(sPorts[slot]); - restore_interrupts(state); - release_sem_etc(cachedSem, 1, B_DO_NOT_RESCHEDULE); + size_t size = copy_port_message(message, _code, buffer, bufferSize, + userCopy); + + sPorts[slot].read_count++; + sPorts[slot].read_condition.NotifyOne(); // we only peeked, but didn't grab the message return size; } - list_remove_link(msg); - + sPorts[slot].messages.RemoveHead(); sPorts[slot].total_count++; + sPorts[slot].write_count++; notify_port_select_events(slot, B_EVENT_WRITE); + sPorts[slot].write_condition.NotifyOne(); + // make one spot in queue available again for write - cachedSem = sPorts[slot].write_sem; + locker.Unlock(); - RELEASE_PORT_LOCK(sPorts[slot]); - restore_interrupts(state); - - // check output buffer size - size = min_c(bufferSize, msg->size); - - // copy message - if (_msgCode != NULL) - *_msgCode = msg->code; - if (size > 0) { - if (userCopy) { - if ((status = cbuf_user_memcpy_from_chain(msgBuffer, msg->buffer_chain, 0, size) < B_OK)) { - // leave the port intact, for other threads that might not crash - put_port_msg(msg); - release_sem(cachedSem); - return status; - } - } else - cbuf_memcpy_from_chain(msgBuffer, msg->buffer_chain, 0, size); - } - put_port_msg(msg); - - // make one spot in queue available again for write - release_sem(cachedSem); - // ToDo: we might think about setting B_NO_RESCHEDULE here - // from time to time (always?) + size_t size = copy_port_message(message, _code, buffer, bufferSize, + userCopy); + put_port_message(message); return size; } status_t -write_port(port_id id, int32 msgCode, const void *msgBuffer, size_t bufferSize) +write_port(port_id id, int32 msgCode, const void* buffer, size_t bufferSize) { - iovec vec = { (void *)msgBuffer, bufferSize }; + iovec vec = { (void*)buffer, bufferSize }; return writev_port_etc(id, msgCode, &vec, 1, bufferSize, 0, 0); } status_t -write_port_etc(port_id id, int32 msgCode, const void *msgBuffer, +write_port_etc(port_id id, int32 msgCode, const void* buffer, size_t bufferSize, uint32 flags, bigtime_t timeout) { - iovec vec = { (void *)msgBuffer, bufferSize }; + iovec vec = { (void*)buffer, bufferSize }; return writev_port_etc(id, msgCode, &vec, 1, bufferSize, flags, timeout); } status_t -writev_port_etc(port_id id, int32 msgCode, const iovec *msgVecs, - size_t vecCount, size_t bufferSize, uint32 flags, - bigtime_t timeout) +writev_port_etc(port_id id, int32 msgCode, const iovec* msgVecs, + size_t vecCount, size_t bufferSize, uint32 flags, bigtime_t timeout) { - cpu_status state; - sem_id cachedSem; - status_t status; - port_msg *msg; - bool userCopy = (flags & PORT_FLAG_USE_USER_MEMCPY) > 0; - int slot; - if (!sPortsActive || id < 0) return B_BAD_PORT_ID; - - // mask irrelevant flags (for acquire_sem() usage) - flags = flags & (B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT - | B_RELATIVE_TIMEOUT | B_ABSOLUTE_TIMEOUT); - slot = id % sMaxPorts; - if (bufferSize > PORT_MAX_MESSAGE_SIZE) return B_BAD_VALUE; - state = disable_interrupts(); - GRAB_PORT_LOCK(sPorts[slot]); + // mask irrelevant flags (for acquire_sem() usage) + flags &= B_CAN_INTERRUPT | B_KILL_CAN_INTERRUPT | B_RELATIVE_TIMEOUT + | B_ABSOLUTE_TIMEOUT; + bool userCopy = (flags & PORT_FLAG_USE_USER_MEMCPY) > 0; + + int32 slot = id % sMaxPorts; + + MutexLocker locker(sPorts[slot].lock); if (sPorts[slot].id != id) { - RELEASE_PORT_LOCK(sPorts[slot]); - restore_interrupts(state); TRACE(("write_port_etc: invalid port_id %ld\n", id)); return B_BAD_PORT_ID; } - if (is_port_closed(slot)) { - RELEASE_PORT_LOCK(sPorts[slot]); - restore_interrupts(state); TRACE(("write_port_etc: port %ld closed\n", id)); return B_BAD_PORT_ID; } - // store sem_id in local variable - cachedSem = sPorts[slot].write_sem; + if (sPorts[slot].write_count-- <= 0) { + // We need to block in order to wait for a free message slot + ConditionVariableEntry entry; + sPorts[slot].write_condition.Add(&entry); - RELEASE_PORT_LOCK(sPorts[slot]); - restore_interrupts(state); + locker.Unlock(); - status = acquire_sem_etc(cachedSem, 1, flags, timeout); - // get 1 entry from the queue, block if needed + status_t status = entry.Wait(flags, timeout); - if (status == B_BAD_SEM_ID) { - // somebody deleted or closed the port - return B_BAD_PORT_ID; + locker.Lock(); + + if (sPorts[slot].id != id) { + // the port is no longer there + 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) - return status; - msg = get_port_msg(msgCode, bufferSize); - if (msg == NULL) { - // Give up our slot in the queue again, and let someone else try and fail - // TODO: try to free some resources and try again? - release_sem(cachedSem); + 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; } // sender credentials - msg->sender = geteuid(); - msg->sender_group = getegid(); - msg->sender_team = team_get_current_team_id(); + message->sender = geteuid(); + message->sender_group = getegid(); + message->sender_team = team_get_current_team_id(); if (bufferSize > 0) { uint32 i; @@ -1213,9 +1007,10 @@ writev_port_etc(port_id id, int32 msgCode, const iovec *msgVecs, if (bytes > bufferSize) bytes = bufferSize; - if ((status = cbuf_user_memcpy_to_chain(msg->buffer_chain, - 0, msgVecs[i].iov_base, bytes)) < B_OK) { - put_port_msg(msg); + status_t status = user_memcpy(message->buffer, + msgVecs[i].iov_base, bytes); + if (status != B_OK) { + put_port_message(message); return status; } @@ -1230,11 +1025,7 @@ writev_port_etc(port_id id, int32 msgCode, const iovec *msgVecs, if (bytes > bufferSize) bytes = bufferSize; - if ((status = cbuf_memcpy_to_chain(msg->buffer_chain, - 0, msgVecs[i].iov_base, bytes)) < 0) { - put_port_msg(msg); - return status; - } + memcpy(message->buffer, msgVecs[i].iov_base, bytes); bufferSize -= bytes; if (bufferSize == 0) @@ -1243,69 +1034,39 @@ writev_port_etc(port_id id, int32 msgCode, const iovec *msgVecs, } } - // attach message to queue - state = disable_interrupts(); - GRAB_PORT_LOCK(sPorts[slot]); - - // first, let's check if the port is still alive - if (sPorts[slot].id == -1) { - // the port has been deleted in the meantime - RELEASE_PORT_LOCK(sPorts[slot]); - restore_interrupts(state); - - put_port_msg(msg); - return B_BAD_PORT_ID; - } - - list_add_item(&sPorts[slot].msg_queue, msg); + sPorts[slot].messages.Add(message); + sPorts[slot].read_count++; notify_port_select_events(slot, B_EVENT_READ); + sPorts[slot].read_condition.NotifyOne(); - // store sem_id in local variable - cachedSem = sPorts[slot].read_sem; - - RELEASE_PORT_LOCK(sPorts[slot]); - restore_interrupts(state); - - // release sem, allowing read (might reschedule) - release_sem(cachedSem); - - return B_NO_ERROR; + return B_OK; } status_t set_port_owner(port_id id, team_id team) { - cpu_status state; - int slot; -// ToDo: Shouldn't we at least check, whether the team exists? - TRACE(("set_port_owner(id = %ld, team = %ld)\n", id, team)); - if (!sPortsActive || id < 0) + 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) { - RELEASE_PORT_LOCK(sPorts[slot]); - restore_interrupts(state); TRACE(("set_port_owner: invalid port_id %ld\n", id)); return B_BAD_PORT_ID; } + if (!team_is_valid(team)) + return B_BAD_TEAM_ID; // transfer ownership to other team sPorts[slot].owner = team; - // unlock port - RELEASE_PORT_LOCK(sPorts[slot]); - restore_interrupts(state); - - return B_NO_ERROR; + return B_OK; } diff --git a/src/system/kernel/util/Jamfile b/src/system/kernel/util/Jamfile index 54a62aa7ed..50ba41b36e 100644 --- a/src/system/kernel/util/Jamfile +++ b/src/system/kernel/util/Jamfile @@ -4,7 +4,6 @@ UsePrivateHeaders [ FDirName kernel util ] ; KernelMergeObject kernel_util.o : AVLTreeMap.cpp - cbuf.c kernel_cpp.cpp khash.c list.c diff --git a/src/system/kernel/util/cbuf.c b/src/system/kernel/util/cbuf.c deleted file mode 100644 index 2f7cea1694..0000000000 --- a/src/system/kernel/util/cbuf.c +++ /dev/null @@ -1,974 +0,0 @@ -/* - * Copyright 2002-2007, Axel Dörfler, axeld@pinc-software.de. All rights reserved. - * Distributed under the terms of the MIT License. - * - * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. - * Distributed under the terms of the NewOS License. - */ - - -/* This file contains the cbuf functions. Cbuf is a memory allocator, - * currently not used for anything in kernel land other than ports. - */ - - -#include - -#include - -#include - -#include -#include - - -#define CBUF_LENGTH 2048 - -#define CBUF_FLAG_CHAIN_HEAD 1 -#define CBUF_FLAG_CHAIN_TAIL 2 - -struct cbuf { - cbuf *next; - size_t length; - size_t total_length; - void *data; - int flags; - - // fill the bytes to let this structure be exactly CBUF_LENGTH bytes large - char dat[CBUF_LENGTH - sizeof(struct cbuf *) - - 2*sizeof(int) - sizeof(void *) - sizeof(int)]; -}; - -#define ALLOCATE_CHUNK (B_PAGE_SIZE * 16) -#define CBUF_REGION_SIZE (4*1024*1024) -#define CBUF_BITMAP_SIZE (CBUF_REGION_SIZE / CBUF_LENGTH) - -static cbuf *sFreeBufferList; -static mutex sFreeBufferListMutex = MUTEX_INITIALIZER("cbuf_free_list"); -static cbuf *sFreeBufferNoBlockList; -static spinlock sNoBlockSpinlock; - -static spinlock sLowlevelSpinlock; -static area_id sBufferArea; -static cbuf *sBuffer; -static area_id sBitmapArea; -static uint8 *sBitmap; - - -/* Declarations we need that aren't in header files */ -//uint16 ones_sum16(uint32, const void *, int); - - -// private part of the API implementation - - -static void -initialize_cbuf(cbuf *buf) -{ - buf->length = sizeof(buf->dat); - buf->data = buf->dat; - buf->flags = 0; - buf->total_length = 0; -} - - -static void * -allocate_cbuf(size_t *_size) -{ - size_t lengthFound = 0; - void *buffer; - int state; - int i; - int start = -1; - -// dprintf("cbuf_alloc: asked to allocate size %d\n", *size); - - state = disable_interrupts(); - acquire_spinlock(&sLowlevelSpinlock); - - // scan through the allocation bitmap, looking for the first free block - // XXX not optimal - for (i = 0; i < CBUF_BITMAP_SIZE; i++) { - if (!CHECK_BIT(sBitmap[i/8], i%8)) { - sBitmap[i/8] = SET_BIT(sBitmap[i/8], i%8); - if (start < 0) - start = i; - - lengthFound += CBUF_LENGTH; - if (lengthFound >= *_size) { - // we're done - break; - } - } else if (start >= 0) { - // we've found a start of a run before, so we're done now - break; - } - } - - if (start < 0) { - // couldn't find any memory - buffer = NULL; - *_size = 0; - } else { - buffer = &sBuffer[start]; - *_size = lengthFound; - } - - release_spinlock(&sLowlevelSpinlock); - restore_interrupts(state); - - return buffer; -} - - -static cbuf * -allocate_cbuf_mem(size_t size) -{ - cbuf *buffer = NULL; - cbuf *lastBuffer = NULL; - cbuf *headBuffer = NULL; - size_t foundSize; - - size = PAGE_ALIGN(size); - - while (size > 0) { - foundSize = size; - buffer = (cbuf *)allocate_cbuf(&foundSize); - if (buffer == NULL) { - // couldn't allocate, lets bail with what we have - break; - } - - size -= foundSize; - - if (headBuffer == NULL) - headBuffer = lastBuffer = buffer; - - while (foundSize > 0) { - initialize_cbuf(buffer); - - headBuffer->total_length += buffer->length; - lastBuffer->next = buffer; - - lastBuffer = buffer; - buffer++; - foundSize -= CBUF_LENGTH; - } - } - - if (headBuffer) { - headBuffer->flags |= CBUF_FLAG_CHAIN_HEAD; - lastBuffer->flags |= CBUF_FLAG_CHAIN_TAIL; - lastBuffer->next = NULL; - } - - return headBuffer; -} - - -static void -clear_chain(cbuf *head, cbuf **tail) -{ - cbuf *buffer; - - buffer = head; - *tail = NULL; - while (buffer) { - initialize_cbuf(buffer); // doesn't touch the next ptr - *tail = buffer; - buffer = buffer->next; - } -} - - -// #pragma mark - -// public part of the API - - -/** Frees the specified buffer chain. Unlike cbuf_free_chain(), - * it doesn't block on a semaphore, but disables interrupts - * to update the non-block list. - */ - -void -cbuf_free_chain_noblock(cbuf *buffer) -{ - cbuf *head, *last; - int state; - - if (buffer == NULL) - return; - - head = buffer; - clear_chain(head, &last); - - state = disable_interrupts(); - acquire_spinlock(&sNoBlockSpinlock); - - last->next = sFreeBufferNoBlockList; - sFreeBufferNoBlockList = head; - - release_spinlock(&sNoBlockSpinlock); - restore_interrupts(state); -} - - -void -cbuf_free_chain(cbuf *buffer) -{ - cbuf *head, *last; - - if (buffer == NULL) - return; - - head = buffer; - clear_chain(head, &last); - - mutex_lock(&sFreeBufferListMutex); - - last->next = sFreeBufferList; - sFreeBufferList = head; - - mutex_unlock(&sFreeBufferListMutex); -} - - -cbuf * -cbuf_get_chain(size_t length) -{ - size_t chainLength = 0; - cbuf *chain = NULL; - cbuf *tail = NULL; - - if (length == 0) - panic("cbuf_get_chain(): passed size 0\n"); - - mutex_lock(&sFreeBufferListMutex); - - while (chainLength < length) { - cbuf *tempBuffer; - - if (sFreeBufferList == NULL) { - // we need to allocate some more cbufs - mutex_unlock(&sFreeBufferListMutex); - - tempBuffer = allocate_cbuf_mem(ALLOCATE_CHUNK); - if (tempBuffer == NULL) { - // no more ram - if (chain) - cbuf_free_chain(chain); - - return NULL; - } - cbuf_free_chain(tempBuffer); - - mutex_lock(&sFreeBufferListMutex); - continue; - } - - tempBuffer = sFreeBufferList; - sFreeBufferList = sFreeBufferList->next; - tempBuffer->next = chain; - if (chain == NULL) - tail = tempBuffer; - chain = tempBuffer; - - chainLength += chain->length; - } - mutex_unlock(&sFreeBufferListMutex); - - // now we have a chain, fixup the first and last entry - chain->total_length = length; - chain->flags |= CBUF_FLAG_CHAIN_HEAD; - tail->length -= chainLength - length; - tail->flags |= CBUF_FLAG_CHAIN_TAIL; - - return chain; -} - - -cbuf * -cbuf_get_chain_noblock(size_t length) -{ - size_t chainLength = 0; - cbuf *chain = NULL; - cbuf *tail = NULL; - int state; - - state = disable_interrupts(); - acquire_spinlock(&sNoBlockSpinlock); - - while (chainLength < length) { - cbuf *tempBuffer; - - if (sFreeBufferNoBlockList == NULL) { - dprintf("cbuf_get_chain_noblock: not enough cbufs\n"); - release_spinlock(&sNoBlockSpinlock); - restore_interrupts(state); - - if (chain != NULL) - cbuf_free_chain_noblock(chain); - - return NULL; - } - - tempBuffer = sFreeBufferNoBlockList; - sFreeBufferNoBlockList = sFreeBufferNoBlockList->next; - tempBuffer->next = chain; - if (chain == NULL) - tail = tempBuffer; - chain = tempBuffer; - - chainLength += chain->length; - } - release_spinlock(&sNoBlockSpinlock); - restore_interrupts(state); - - // now we have a chain, fixup the first and last entry - chain->total_length = length; - chain->flags |= CBUF_FLAG_CHAIN_HEAD; - tail->length -= chainLength - length; - tail->flags |= CBUF_FLAG_CHAIN_TAIL; - - return chain; -} - - -status_t -cbuf_memcpy_to_chain(cbuf *chain, size_t offset, const void *_source, size_t length) -{ - cbuf *buffer; - char *source = (char *)_source; - int bufferOffset; - - if (chain == NULL) - return B_BAD_VALUE; - - if ((chain->flags & CBUF_FLAG_CHAIN_HEAD) == 0) { - dprintf("cbuf_memcpy_to_chain: chain at %p not head\n", chain); - return B_BAD_VALUE; - } - - if (length + offset > chain->total_length) { - dprintf("cbuf_memcpy_to_chain: length + offset > size of cbuf chain\n"); - return B_BAD_VALUE; - } - - // find the starting cbuf in the chain to copy to - buffer = chain; - bufferOffset = 0; - - while (offset > 0) { - if (buffer == NULL) { - dprintf("cbuf_memcpy_to_chain: end of chain reached too early!\n"); - return B_ERROR; - } - - if (offset < buffer->length) { - // this is the one - bufferOffset = offset; - break; - } - - offset -= buffer->length; - buffer = buffer->next; - } - - while (length > 0) { - int toCopy; - - if (buffer == NULL) { - dprintf("cbuf_memcpy_to_chain: end of chain reached too early!\n"); - return B_ERROR; - } - - toCopy = min(length, buffer->length - bufferOffset); - memcpy((char *)buffer->data + bufferOffset, source, toCopy); - - bufferOffset = 0; - length -= toCopy; - source += toCopy; - buffer = buffer->next; - } - - return B_OK; -} - - -status_t -cbuf_user_memcpy_to_chain(cbuf *chain, size_t offset, const void *_source, size_t length) -{ - cbuf *buffer; - char *source = (char *)_source; - int bufferOffset; - int err; - - if (chain == NULL) - return B_BAD_VALUE; - - if ((chain->flags & CBUF_FLAG_CHAIN_HEAD) == 0) { - dprintf("cbuf_memcpy_to_chain: chain at %p not head\n", chain); - return B_BAD_VALUE; - } - - if (length + offset > chain->total_length) { - dprintf("cbuf_memcpy_to_chain: length + offset > size of cbuf chain\n"); - return B_BAD_VALUE; - } - - // find the starting cbuf in the chain to copy to - buffer = chain; - bufferOffset = 0; - - while (offset > 0) { - if (buffer == NULL) { - dprintf("cbuf_memcpy_to_chain: end of chain reached too early!\n"); - return B_ERROR; - } - - if (offset < buffer->length) { - // this is the one - bufferOffset = offset; - break; - } - - offset -= buffer->length; - buffer = buffer->next; - } - - err = B_NO_ERROR; - - while (length > 0) { - int toCopy; - - if (buffer == NULL) { - dprintf("cbuf_memcpy_to_chain: end of chain reached too early!\n"); - return B_ERROR; - } - toCopy = min(length, buffer->length - bufferOffset); - - err = user_memcpy((char *)buffer->data + bufferOffset, source, toCopy); - if (err < 0) - break; // memory exception - - bufferOffset = 0; - length -= toCopy; - source += toCopy; - buffer = buffer->next; - } - - return err; -} - - -status_t -cbuf_memcpy_from_chain(void *_dest, cbuf *chain, size_t offset, size_t length) -{ - cbuf *buffer; - char *dest = (char *)_dest; - int bufferOffset; - - if (chain == NULL) - return B_BAD_VALUE; - - if ((chain->flags & CBUF_FLAG_CHAIN_HEAD) == 0) { - dprintf("cbuf_memcpy_from_chain: chain at %p not head\n", chain); - return B_BAD_VALUE; - } - - if (length + offset > chain->total_length) { - dprintf("cbuf_memcpy_from_chain: length + offset > size of cbuf chain\n"); - return B_BAD_VALUE; - } - - // find the starting cbuf in the chain to copy from - buffer = chain; - bufferOffset = 0; - - while (offset > 0) { - if (buffer == NULL) { - dprintf("cbuf_memcpy_from_chain: end of chain reached too early!\n"); - return B_ERROR; - } - - if (offset < buffer->length) { - // this is the one - bufferOffset = offset; - break; - } - offset -= buffer->length; - buffer = buffer->next; - } - - while (length > 0) { - int toCopy; - - if (buffer == NULL) { - dprintf("cbuf_memcpy_from_chain: end of chain reached too early!\n"); - return B_ERROR; - } - - toCopy = min(length, buffer->length - bufferOffset); - memcpy(dest, (char *)buffer->data + bufferOffset, toCopy); - - bufferOffset = 0; - length -= toCopy; - dest += toCopy; - buffer = buffer->next; - } - - return B_OK; -} - - -status_t -cbuf_user_memcpy_from_chain(void *_dest, cbuf *chain, size_t offset, size_t length) -{ - cbuf *buffer; - char *dest = (char *)_dest; - int bufferOffset; - int err; - - if (length == 0) - return B_OK; - if (chain == NULL) - return B_BAD_VALUE; - - if ((chain->flags & CBUF_FLAG_CHAIN_HEAD) == 0) { - dprintf("cbuf_memcpy_from_chain: chain at %p not head\n", chain); - return B_BAD_VALUE; - } - - if (length + offset > chain->total_length) { - dprintf("cbuf_memcpy_from_chain: length + offset > size of cbuf chain\n"); - return B_BAD_VALUE; - } - - // find the starting cbuf in the chain to copy from - buffer = chain; - bufferOffset = 0; - - while (offset > 0) { - if (buffer == NULL) { - dprintf("cbuf_memcpy_from_chain: end of chain reached too early!\n"); - return B_ERROR; - } - - if (offset < buffer->length) { - // this is the one - bufferOffset = offset; - break; - } - offset -= buffer->length; - buffer = buffer->next; - } - - err = B_NO_ERROR; - - while (length > 0) { - int toCopy; - - if (buffer == NULL) { - dprintf("cbuf_memcpy_from_chain: end of chain reached too early!\n"); - return B_ERROR; - } - - toCopy = min(length, buffer->length - bufferOffset); - - err = user_memcpy(dest, (char *)buffer->data + bufferOffset, toCopy); - if (err < 0) - break; - - bufferOffset = 0; - length -= toCopy; - dest += toCopy; - buffer = buffer->next; - } - - return err; -} - - -cbuf * -cbuf_duplicate_chain(cbuf *chain, size_t offset, size_t length) -{ - cbuf *buffer; - cbuf *newBuffer; - cbuf *destBuffer; - int destBufferOffset; - int bufferOffset; - - if (chain == NULL) - return NULL; - - if ((chain->flags & CBUF_FLAG_CHAIN_HEAD) == 0) - return NULL; - if (offset >= chain->total_length) - return NULL; - - length = min(length, chain->total_length - offset); - - newBuffer = cbuf_get_chain(length); - if (!newBuffer) - return NULL; - - // find the starting cbuf in the chain to copy from - buffer = chain; - bufferOffset = 0; - while (offset > 0) { - if (buffer == NULL) { - cbuf_free_chain(newBuffer); - dprintf("cbuf_duplicate_chain: end of chain reached too early!\n"); - return NULL; - } - if (offset < buffer->length) { - // this is the one - bufferOffset = offset; - break; - } - offset -= buffer->length; - buffer = buffer->next; - } - - destBuffer = newBuffer; - destBufferOffset = 0; - - while (length > 0) { - size_t toCopy; - - if (buffer == NULL) { - cbuf_free_chain(newBuffer); - dprintf("cbuf_duplicate_chain: end of source chain reached too early!\n"); - return NULL; - } - if (destBuffer == NULL) { - cbuf_free_chain(newBuffer); - dprintf("cbuf_duplicate_chain: end of destination chain reached too early!\n"); - return NULL; - } - - toCopy = min(destBuffer->length - destBufferOffset, buffer->length - bufferOffset); - toCopy = min(toCopy, length); - memcpy((char *)destBuffer->data + destBufferOffset, (char *)buffer->data + bufferOffset, toCopy); - - length -= toCopy; - if (toCopy + bufferOffset == buffer->length) { - buffer = buffer->next; - bufferOffset = 0; - } else - bufferOffset += toCopy; - - if (toCopy + destBufferOffset == destBuffer->length) { - destBuffer = destBuffer->next; - destBufferOffset = 0; - } else - destBufferOffset += toCopy; - } - - return newBuffer; -} - - -cbuf * -cbuf_merge_chains(cbuf *chain1, cbuf *chain2) -{ - cbuf *buffer; - - if (!chain1 && !chain2) - return NULL; - - if (!chain1) - return chain2; - if (!chain2) - return chain1; - - if ((chain1->flags & CBUF_FLAG_CHAIN_HEAD) == 0) { - dprintf("cbuf_merge_chain: chain at %p not head\n", chain1); - return NULL; - } - - if ((chain2->flags & CBUF_FLAG_CHAIN_HEAD) == 0) { - dprintf("cbuf_merge_chain: chain at %p not head\n", chain2); - return NULL; - } - - // walk to the end of the first chain and tag the second one on - buffer = chain1; - while (buffer->next) - buffer = buffer->next; - - buffer->next = chain2; - - // modify the flags on the chain headers - buffer->flags &= ~CBUF_FLAG_CHAIN_TAIL; - chain1->total_length += chain2->total_length; - chain2->flags &= ~CBUF_FLAG_CHAIN_HEAD; - - return chain1; -} - - -size_t -cbuf_get_length(cbuf *buffer) -{ - if (buffer == NULL) - return 0; - - if (buffer->flags & CBUF_FLAG_CHAIN_HEAD) { - return buffer->total_length; - } else { - int length = 0; - while (buffer) { - length += buffer->length; - buffer = buffer->next; - } - return length; - } -} - - -void * -cbuf_get_ptr(cbuf *buffer, size_t offset) -{ - while (buffer) { - if (buffer->length > offset) - return (void *)((int)buffer->data + offset); - - offset -= buffer->length; - buffer = buffer->next; - } - return NULL; -} - - -/** Returns true if the buffer chain is contiguous over - * the specified range. - */ - -bool -cbuf_is_contig_region(cbuf *buffer, size_t start, size_t end) -{ - while (buffer) { - if (buffer->length > start) - return buffer->length - start >= end; - - start -= buffer->length; - end -= buffer->length; - buffer = buffer->next; - } - return 0; -} - -#if 0 -uint16 -cbuf_ones_cksum16(cbuf *buffer, size_t offset, size_t length) -{ - uint16 sum = 0; - int swapped = 0; - - if (buffer == NULL - || (buffer->flags & CBUF_FLAG_CHAIN_HEAD) == 0) - return 0; - - // find the start ptr - while (buffer) { - if (buffer->length > offset) - break; - - offset -= buffer->length; - buffer = buffer->next; - } - - // start checksumming - while (buffer && length > 0) { - void *ptr = (void *)((addr_t)buffer->data + offset); - size_t plen = min(length, buffer->length - offset); - - sum = ones_sum16(sum, ptr, plen); - - length -= plen; - buffer = buffer->next; - - // if the pointer was odd, or the length was odd, but not both, - // the checksum was swapped - if ((buffer && length > 0) - && (((offset % 2) && (plen % 2) == 0) || (((offset % 2) == 0) && (plen % 2)))) { - swapped ^= 1; - sum = ((sum & 0xff) << 8) | ((sum >> 8) & 0xff); - } - offset = 0; - } - - if (swapped) - sum = ((sum & 0xff) << 8) | ((sum >> 8) & 0xff); - - return ~sum; -} -#endif - -/** Truncates the head of the buffer chain about truncBytes. - */ - -status_t -cbuf_truncate_head(cbuf *buffer, size_t truncBytes) -{ - cbuf *head = buffer; - - if (!buffer || (buffer->flags & CBUF_FLAG_CHAIN_HEAD) == 0) - return B_BAD_VALUE; - - while (buffer && truncBytes > 0) { - int toTrunc = min(truncBytes, buffer->length); - - buffer->length -= toTrunc; - buffer->data = (void *)((int)buffer->data + toTrunc); - - truncBytes -= toTrunc; - head->total_length -= toTrunc; - buffer = buffer->next; - } - - return B_OK; -} - - -/** Truncate the tail of the buffer chain about truncBytes. - */ - -status_t -cbuf_truncate_tail(cbuf *buffer, size_t truncBytes) -{ - cbuf *head = buffer; - size_t offset; - - if (!buffer || (buffer->flags & CBUF_FLAG_CHAIN_HEAD) == 0) - return B_BAD_VALUE; - - // we can't remove more than there is - if (truncBytes > head->total_length) - truncBytes = head->total_length; - - offset = buffer->total_length - truncBytes; - - while (buffer) { - if (offset < buffer->length) - break; - - offset -= buffer->length; - buffer = buffer->next; - } - if (!buffer) - return B_ERROR; - - head->total_length -= buffer->length - offset; - buffer->length = offset; - - // clear out the rest of the buffers in this chain - while ((buffer = buffer->next) != NULL) { - head->total_length -= buffer->length; - buffer->length = 0; - } - - return B_OK; -} - - -// #pragma mark - - - -static int -dbg_dump_cbuf_freelists(int argc, char **argv) -{ - cbuf *buffer; - - kprintf("sFreeBufferList:\n"); - for (buffer = sFreeBufferList; buffer; buffer = buffer->next) - kprintf("%p ", buffer); - kprintf("\n"); - - kprintf("sFreeBufferNoBlockList:\n"); - for (buffer = sFreeBufferNoBlockList; buffer; buffer = buffer->next) - kprintf("%p ", buffer); - kprintf("\n"); - - return 0; -} - - -void -cbuf_test(void) -{ - cbuf *buffer, *buffer2; - char temp[1024]; - unsigned int i; - - dprintf("starting cbuffer test\n"); - - buffer = cbuf_get_chain(32); - if (!buffer) - panic("cbuf_test: failed allocation of 32\n"); - - buffer2 = cbuf_get_chain(3*1024*1024); - if (!buffer2) - panic("cbuf_test: failed allocation of 3mb\n"); - - buffer = cbuf_merge_chains(buffer2, buffer); - - cbuf_free_chain(buffer); - - dprintf("allocating too much...\n"); - - buffer = cbuf_get_chain(128*1024*1024); - if (buffer) - panic("cbuf_test: should have failed to allocate 128mb\n"); - - dprintf("touching memory allocated by cbuf\n"); - - buffer = cbuf_get_chain(7*1024*1024); - if (!buffer) - panic("cbuf_test: failed allocation of 7mb\n"); - - for (i = 0; i < sizeof(temp); i++) - temp[i] = i; - for (i = 0; i < 7*1024*1024 / sizeof(temp); i++) { - if (i % 128 == 0) - dprintf("%Lud\n", (long long)(i*sizeof(temp))); - cbuf_memcpy_to_chain(buffer, i*sizeof(temp), temp, sizeof(temp)); - } - cbuf_free_chain(buffer); - - dprintf("finished cbuffer test\n"); -} - - -status_t -cbuf_init(void) -{ - int i; - - // add the debug command - add_debugger_command("cbuf_freelist", &dbg_dump_cbuf_freelists, "Dumps the cbuf free lists"); - - // errors are fatal, that's why we don't clean up here - - sBufferArea = create_area("cbuf region", (void **)&sBuffer, - B_ANY_KERNEL_ADDRESS, CBUF_REGION_SIZE, B_FULL_LOCK, - B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); - if (sBufferArea < 0) { - panic("cbuf_init: error creating cbuf region\n"); - return B_NO_MEMORY; - } - - sBitmapArea = create_area("cbuf bitmap region", (void **)&sBitmap, B_ANY_KERNEL_ADDRESS, - CBUF_BITMAP_SIZE / 8, B_FULL_LOCK, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); - if (sBitmapArea < 0) { - panic("cbuf_init: error creating cbuf bitmap region\n"); - return B_NO_MEMORY; - } - - // initialize the bitmap - for (i = 0; i < CBUF_BITMAP_SIZE / 8; i++) - sBitmap[i] = 0; - - return B_OK; -}