diff --git a/headers/private/kernel/port.h b/headers/private/kernel/port.h index 9f64bd60f2..9c4d22aaa2 100644 --- a/headers/private/kernel/port.h +++ b/headers/private/kernel/port.h @@ -32,7 +32,7 @@ extern "C" { #endif status_t port_init(struct kernel_args *args); -int delete_owned_ports(team_id owner); +void delete_owned_ports(struct team* team); int32 port_max_ports(void); int32 port_used_ports(void); @@ -41,11 +41,8 @@ status_t deselect_port(int32 object, struct select_info *info, bool kernel); // currently private API status_t writev_port_etc(port_id id, int32 msgCode, const iovec *msgVecs, - size_t vecCount, size_t bufferSize, uint32 flags, - bigtime_t timeout); - -// temp: test -void port_test(void); + size_t vecCount, size_t bufferSize, uint32 flags, + bigtime_t timeout); // user syscalls port_id _user_create_port(int32 queueLength, const char *name); diff --git a/headers/private/kernel/thread_types.h b/headers/private/kernel/thread_types.h index 18e52c9da2..9f7f3d30ec 100644 --- a/headers/private/kernel/thread_types.h +++ b/headers/private/kernel/thread_types.h @@ -194,6 +194,7 @@ struct team { struct list image_list; struct list watcher_list; struct list sem_list; + struct list port_list; struct arch_team arch_info; addr_t user_data; diff --git a/src/system/kernel/port.cpp b/src/system/kernel/port.cpp index 24355cdc5d..fcb05e3e17 100644 --- a/src/system/kernel/port.cpp +++ b/src/system/kernel/port.cpp @@ -52,6 +52,7 @@ struct port_message : DoublyLinkedListLinkImpl { typedef DoublyLinkedList MessageList; struct port_entry { + struct list_link team_link; port_id id; team_id owner; int32 capacity; @@ -563,38 +564,52 @@ copy_port_message(port_message* message, int32* _code, void* buffer, } +static void +uninit_port_locked(struct port_entry& port) +{ + int32 id = port.id; + + // mark port as invalid + port.id = -1; + free((char*)port.lock.name); + port.lock.name = NULL; + + while (port_message* message = port.messages.RemoveHead()) { + put_port_message(message); + } + + notify_port_select_events(id % sMaxPorts, B_EVENT_INVALID); + port.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 + port.read_condition.NotifyAll(B_BAD_PORT_ID); + port.write_condition.NotifyAll(B_BAD_PORT_ID); + sNotificationService.Notify(PORT_REMOVED, id); +} + + // #pragma mark - private kernel API -/*! This function cycles through the ports table, deleting all - the ports that are owned by the passed team_id +/*! This function delets all the ports that are owned by the passed team. */ -int -delete_owned_ports(team_id owner) +void +delete_owned_ports(struct team* team) { - // TODO: investigate maintaining a list of ports in the team - // to make this simpler and more efficient. + TRACE(("delete_owned_ports(owner = %ld)\n", team->id)); - TRACE(("delete_owned_ports(owner = %ld)\n", owner)); + struct list queue; - MutexLocker locker(sPortsLock); - - int32 count = 0; - - for (int32 i = 0; i < sMaxPorts; i++) { - if (sPorts[i].id != -1 && sPorts[i].owner == owner) { - port_id id = sPorts[i].id; - - locker.Unlock(); - - delete_port(id); - count++; - - locker.Lock(); - } + { + InterruptsSpinLocker locker(gTeamSpinlock); + list_move_to_list(&team->port_list, &queue); } - return count; + while (port_entry* port = (port_entry*)list_remove_head_item(&queue)) { + MutexLocker locker(port->lock); + uninit_port_locked(*port); + } } @@ -693,6 +708,10 @@ create_port(int32 queueLength, const char* name) if (queueLength < 1 || queueLength > MAX_QUEUE_LENGTH) return B_BAD_VALUE; + struct team* team = thread_get_current_thread()->team; + if (team == NULL) + return B_BAD_TEAM_ID; + MutexLocker locker(sPortsLock); // check early on if there are any free port slots to use @@ -730,6 +749,11 @@ create_port(int32 queueLength, const char* name) sPorts[i].total_count = 0; sPorts[i].select_infos = NULL; + { + InterruptsSpinLocker teamLocker(gTeamSpinlock); + list_add_item(&team->port_list, &sPorts[i].team_link); + } + port_id id = sPorts[i].id; T(Create(sPorts[i])); @@ -800,23 +824,12 @@ delete_port(port_id id) T(Delete(sPorts[slot])); - // mark port as invalid - sPorts[slot].id = -1; - free((char*)sPorts[slot].lock.name); - sPorts[slot].lock.name = NULL; - - while (port_message* message = sPorts[slot].messages.RemoveHead()) { - put_port_message(message); + { + InterruptsSpinLocker teamLocker(gTeamSpinlock); + list_remove_link(&sPorts[slot].team_link); } - 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); + uninit_port_locked(sPorts[slot]); locker.Unlock(); diff --git a/src/system/kernel/team.cpp b/src/system/kernel/team.cpp index fd13363385..c17b058b61 100644 --- a/src/system/kernel/team.cpp +++ b/src/system/kernel/team.cpp @@ -7,8 +7,10 @@ * Distributed under the terms of the NewOS License. */ + /*! Team functions */ + #include #include #include @@ -798,6 +800,7 @@ create_team_struct(const char *name, bool kernel) team->job_control_entry->team = team; list_init(&team->sem_list); + list_init(&team->port_list); list_init(&team->image_list); list_init(&team->watcher_list); @@ -1392,7 +1395,7 @@ exec_team(const char *path, char**& _flatArgs, size_t flatArgsSize, delete_team_user_data(team); vm_delete_areas(team->address_space); xsi_sem_undo(team); - delete_owned_ports(team->id); + delete_owned_ports(team); sem_delete_owned_sems(team); remove_images(team); vfs_exec_io_context(team->io_context); @@ -2463,7 +2466,7 @@ team_delete_team(struct team *team) vfs_put_io_context(team->io_context); delete_realtime_sem_context(team->realtime_sem_context); xsi_sem_undo(team); - delete_owned_ports(teamID); + delete_owned_ports(team); sem_delete_owned_sems(team); remove_images(team); vm_delete_address_space(team->address_space);