* IDs are now generally printed as decimal values.

* Removed old port test code, it doesn't belong there.
* Cleanup.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@22507 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2007-10-11 08:30:18 +00:00
parent f8941839c3
commit 7861bd3cfb
2 changed files with 188 additions and 315 deletions

View File

@ -6,7 +6,7 @@
* Distributed under the terms of the NewOS License. * Distributed under the terms of the NewOS License.
*/ */
/* ports for IPC */ /*! Ports for IPC */
#include <OS.h> #include <OS.h>
@ -54,19 +54,14 @@ struct port_entry {
struct list msg_queue; struct list msg_queue;
}; };
// internal API
static int dump_port_list(int argc, char **argv);
static int dump_port_info(int argc, char **argv);
static void _dump_port_info(struct port_entry *port);
#define MAX_QUEUE_LENGTH 4096
#define PORT_MAX_MESSAGE_SIZE 65536
// sMaxPorts must be power of 2 // sMaxPorts must be power of 2
static int32 sMaxPorts = 4096; static int32 sMaxPorts = 4096;
static int32 sUsedPorts = 0; static int32 sUsedPorts = 0;
#define MAX_QUEUE_LENGTH 4096
#define PORT_MAX_MESSAGE_SIZE 65536
static struct port_entry *sPorts = NULL; static struct port_entry *sPorts = NULL;
static area_id sPortArea = 0; static area_id sPortArea = 0;
static bool sPortsActive = false; static bool sPortsActive = false;
@ -81,143 +76,7 @@ static spinlock sPortSpinlock = 0;
#define RELEASE_PORT_LOCK(s) release_spinlock(&(s).lock) #define RELEASE_PORT_LOCK(s) release_spinlock(&(s).lock)
status_t static int
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);
if (sPortArea < 0) {
panic("unable to allocate kernel port table!\n");
}
// 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++)
sPorts[i].id = -1;
// add debugger commands
add_debugger_command("ports", &dump_port_list, "Dump a list of all active ports");
add_debugger_command("port", &dump_port_info, "Dump info about a particular port");
sPortsActive = true;
return 0;
}
#ifdef DEBUG
// ToDo: the test code does not belong here!
// the same code is present in the test_app in kernel/apps
// so I guess we can remove this
/*
* testcode
*/
static int32 port_test_thread_func(void *arg);
port_id test_p1, test_p2, test_p3, test_p4;
void
port_test()
{
char testdata[5];
thread_id t;
int res;
int32 dummy;
int32 dummy2;
strcpy(testdata, "abcd");
dprintf("porttest: create_port()\n");
test_p1 = create_port(1, "test port #1");
test_p2 = create_port(10, "test port #2");
test_p3 = create_port(1024, "test port #3");
test_p4 = create_port(1024, "test port #4");
dprintf("porttest: find_port()\n");
dprintf("'test port #1' has id %ld (should be %ld)\n", find_port("test port #1"), test_p1);
dprintf("porttest: write_port() on 1, 2 and 3\n");
write_port(test_p1, 1, &testdata, sizeof(testdata));
write_port(test_p2, 666, &testdata, sizeof(testdata));
write_port(test_p3, 999, &testdata, sizeof(testdata));
dprintf("porttest: port_count(test_p1) = %ld\n", port_count(test_p1));
dprintf("porttest: write_port() on 1 with timeout of 1 sec (blocks 1 sec)\n");
write_port_etc(test_p1, 1, &testdata, sizeof(testdata), B_TIMEOUT, 1000000);
dprintf("porttest: write_port() on 2 with timeout of 1 sec (wont block)\n");
res = write_port_etc(test_p2, 777, &testdata, sizeof(testdata), B_TIMEOUT, 1000000);
dprintf("porttest: res=%d, %s\n", res, res == 0 ? "ok" : "BAD");
dprintf("porttest: read_port() on empty port 4 with timeout of 1 sec (blocks 1 sec)\n");
res = read_port_etc(test_p4, &dummy, &dummy2, sizeof(dummy2), B_TIMEOUT, 1000000);
dprintf("porttest: res=%d, %s\n", res, res == B_TIMED_OUT ? "ok" : "BAD");
dprintf("porttest: spawning thread for port 1\n");
t = spawn_kernel_thread(port_test_thread_func, "port_test", B_NORMAL_PRIORITY, NULL);
resume_thread(t);
dprintf("porttest: write\n");
write_port(test_p1, 1, &testdata, sizeof(testdata));
// now we can write more (no blocking)
dprintf("porttest: write #2\n");
write_port(test_p1, 2, &testdata, sizeof(testdata));
dprintf("porttest: write #3\n");
write_port(test_p1, 3, &testdata, sizeof(testdata));
dprintf("porttest: waiting on spawned thread\n");
wait_for_thread(t, NULL);
dprintf("porttest: close p1\n");
close_port(test_p2);
dprintf("porttest: attempt write p1 after close\n");
res = write_port(test_p2, 4, &testdata, sizeof(testdata));
dprintf("porttest: write_port ret %d\n", res);
dprintf("porttest: testing delete p2\n");
delete_port(test_p2);
dprintf("porttest: end test main thread\n");
}
static int32
port_test_thread_func(void *arg)
{
int32 msg_code;
int n;
char buf[6];
buf[5] = '\0';
dprintf("porttest: port_test_thread_func()\n");
n = read_port(test_p1, &msg_code, &buf, 3);
dprintf("read_port #1 code %ld len %d buf %s\n", msg_code, n, buf);
n = read_port(test_p1, &msg_code, &buf, 4);
dprintf("read_port #1 code %ld len %d buf %s\n", msg_code, n, buf);
buf[4] = 'X';
n = read_port(test_p1, &msg_code, &buf, 5);
dprintf("read_port #1 code %ld len %d buf %s\n", msg_code, n, buf);
dprintf("porttest: testing delete p1 from other thread\n");
delete_port(test_p1);
dprintf("porttest: end port_test_thread_func()\n");
return 0;
}
#endif /* DEBUG */
int
dump_port_list(int argc, char **argv) dump_port_list(int argc, char **argv)
{ {
const char *name = NULL; const char *name = NULL;
@ -241,8 +100,9 @@ dump_port_list(int argc, char **argv)
|| (name != NULL && strstr(port->name, name) == NULL)) || (name != NULL && strstr(port->name, name) == NULL))
continue; continue;
kprintf("%p %6lx %4ld %6lx %6lx %6lx %s\n", port, port->id, port->capacity, kprintf("%p %6ld %4ld %6ld %6ld %6ld %s\n", port, port->id,
port->read_sem, port->write_sem, port->owner, port->name); port->capacity, port->read_sem, port->write_sem, port->owner,
port->name);
} }
return 0; return 0;
} }
@ -293,7 +153,7 @@ dump_port_info(int argc, char **argv)
uint32 num = strtoul(argv[1], NULL, 0); uint32 num = strtoul(argv[1], NULL, 0);
uint32 slot = num % sMaxPorts; uint32 slot = num % sMaxPorts;
if (sPorts[slot].id != (int)num) { if (sPorts[slot].id != (int)num) {
kprintf("port 0x%lx doesn't exist!\n", num); kprintf("port %ld (%#lx) doesn't exist!\n", num, num);
return 0; return 0;
} }
_dump_port_info(&sPorts[slot]); _dump_port_info(&sPorts[slot]);
@ -303,8 +163,10 @@ dump_port_info(int argc, char **argv)
// walk through the ports list, trying to match name // walk through the ports list, trying to match name
for (i = 0; i < sMaxPorts; i++) { for (i = 0; i < sMaxPorts; i++) {
if ((name != NULL && sPorts[i].name != NULL && !strcmp(name, sPorts[i].name)) if ((name != NULL && sPorts[i].name != NULL
|| (sem != -1 && (sPorts[i].read_sem == sem || sPorts[i].write_sem == sem))) { && !strcmp(name, sPorts[i].name))
|| (sem != -1 && (sPorts[i].read_sem == sem
|| sPorts[i].write_sem == sem))) {
_dump_port_info(&sPorts[i]); _dump_port_info(&sPorts[i]);
return 0; return 0;
} }
@ -322,10 +184,77 @@ notify_port_select_events(int slot, uint16 events)
} }
/** this function cycles through the ports table, deleting all static void
* the ports that are owned by the passed team_id put_port_msg(port_msg *msg)
*/ {
cbuf_free_chain(msg->buffer_chain);
free(msg);
}
static port_msg *
get_port_msg(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)
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;
}
/*! You need to own the port's lock when calling this function */
static bool
is_port_closed(int32 slot)
{
return sPorts[slot].capacity == 0;
}
/*! Fills the port_info structure with information from the specified
port.
The port lock must be held when called.
*/
static void
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);
if (count < 0)
count = 0;
info->queue_count = count;
info->total_count = port->total_count;
strlcpy(info->name, port->name, B_OS_NAME_LENGTH);
}
// #pragma mark - private kernel API
/*! This function cycles through the ports table, deleting all
the ports that are owned by the passed team_id
*/
int int
delete_owned_ports(team_id owner) delete_owned_ports(team_id owner)
{ {
@ -365,48 +294,6 @@ delete_owned_ports(team_id owner)
} }
static void
put_port_msg(port_msg *msg)
{
cbuf_free_chain(msg->buffer_chain);
free(msg);
}
static port_msg *
get_port_msg(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)
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;
}
/** You need to own the port's lock when calling this function */
static bool
is_port_closed(int32 slot)
{
return sPorts[slot].capacity == 0;
}
int32 int32
port_max_ports(void) port_max_ports(void)
{ {
@ -421,6 +308,37 @@ port_used_ports(void)
} }
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);
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++)
sPorts[i].id = -1;
// add debugger commands
add_debugger_command("ports", &dump_port_list, "Dump a list of all active ports");
add_debugger_command("port", &dump_port_info, "Dump info about a particular port");
sPortsActive = true;
return B_OK;
}
// #pragma mark - public kernel API // #pragma mark - public kernel API
@ -778,31 +696,6 @@ find_port(const char *name)
} }
/** Fills the port_info structure with information from the specified
* port.
* The port lock must be held when called.
*/
static void
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);
if (count < 0)
count = 0;
info->queue_count = count;
info->total_count = port->total_count;
strlcpy(info->name, port->name, B_OS_NAME_LENGTH);
}
status_t 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)
{ {

View File

@ -6,7 +6,7 @@
* Distributed under the terms of the NewOS License. * Distributed under the terms of the NewOS License.
*/ */
/* Team functions */ /*! Team functions */
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
@ -88,27 +88,27 @@ static void
_dump_team_info(struct team *team) _dump_team_info(struct team *team)
{ {
kprintf("TEAM: %p\n", team); kprintf("TEAM: %p\n", team);
kprintf("id: 0x%lx\n", team->id); kprintf("id: %ld (%#lx)\n", team->id, team->id);
kprintf("name: '%s'\n", team->name); kprintf("name: '%s'\n", team->name);
kprintf("args: '%s'\n", team->args); kprintf("args: '%s'\n", team->args);
kprintf("next: %p\n", team->next); kprintf("next: %p\n", team->next);
kprintf("parent: %p", team->parent); kprintf("parent: %p", team->parent);
if (team->parent != NULL) { if (team->parent != NULL) {
kprintf(" (id = 0x%lx)\n", team->parent->id); kprintf(" (id = %ld)\n", team->parent->id);
} else } else
kprintf("\n"); kprintf("\n");
kprintf("children: %p\n", team->children); kprintf("children: %p\n", team->children);
kprintf("num_threads: %d\n", team->num_threads); kprintf("num_threads: %d\n", team->num_threads);
kprintf("state: %d\n", team->state); kprintf("state: %d\n", team->state);
kprintf("pending_signals: 0x%x\n", team->pending_signals); kprintf("pending_signals: %#x\n", team->pending_signals);
kprintf("io_context: %p\n", team->io_context); kprintf("io_context: %p\n", team->io_context);
if (team->address_space) if (team->address_space)
kprintf("address_space: %p (id = 0x%lx)\n", team->address_space, team->address_space->id); kprintf("address_space: %p\n", team->address_space);
kprintf("main_thread: %p\n", team->main_thread); kprintf("main_thread: %p\n", team->main_thread);
kprintf("thread_list: %p\n", team->thread_list); kprintf("thread_list: %p\n", team->thread_list);
kprintf("group_id: 0x%lx\n", team->group_id); kprintf("group_id: %ld\n", team->group_id);
kprintf("session_id: 0x%lx\n", team->session_id); kprintf("session_id: %ld\n", team->session_id);
} }
@ -167,12 +167,11 @@ dump_teams(int argc, char **argv)
} }
/** Frees an array of strings in kernel space. /*! Frees an array of strings in kernel space.
*
* \param strings strings array
* \param count number of strings in array
*/
\param strings strings array
\param count number of strings in array
*/
static void static void
free_strings_array(char **strings, int32 count) free_strings_array(char **strings, int32 count)
{ {
@ -188,15 +187,14 @@ free_strings_array(char **strings, int32 count)
} }
/** Copy an array of strings in kernel space /*! Copy an array of strings in kernel space
*
* \param strings strings array to be copied
* \param count number of strings in array
* \param kstrings pointer to the kernel copy
* \return \c B_OK on success, or an appropriate error code on
* failure.
*/
\param strings strings array to be copied
\param count number of strings in array
\param kstrings pointer to the kernel copy
\return \c B_OK on success, or an appropriate error code on
failure.
*/
static status_t static status_t
kernel_copy_strings_array(char * const *in, int32 count, char ***_strings) kernel_copy_strings_array(char * const *in, int32 count, char ***_strings)
{ {
@ -227,15 +225,14 @@ error:
} }
/** Copy an array of strings from user space to kernel space /*! Copy an array of strings from user space to kernel space
*
* \param strings userspace strings array
* \param count number of strings in array
* \param kstrings pointer to the kernel copy
* \return \c B_OK on success, or an appropriate error code on
* failure.
*/
\param strings userspace strings array
\param count number of strings in array
\param kstrings pointer to the kernel copy
\return \c B_OK on success, or an appropriate error code on
failure.
*/
static status_t static status_t
user_copy_strings_array(char * const *userStrings, int32 count, char ***_strings) user_copy_strings_array(char * const *userStrings, int32 count, char ***_strings)
{ {
@ -365,9 +362,7 @@ insert_team_into_parent(struct team *parent, struct team *team)
} }
/** Note: must have TEAM lock held /*! Note: must have team lock held */
*/
static void static void
remove_team_from_parent(struct team *parent, struct team *team) remove_team_from_parent(struct team *parent, struct team *team)
{ {
@ -388,10 +383,9 @@ remove_team_from_parent(struct team *parent, struct team *team)
} }
/** Reparent each of our children /*! Reparent each of our children
* Note: must have TEAM lock held Note: must have team lock held
*/ */
static void static void
reparent_children(struct team *team) reparent_children(struct team *team)
{ {
@ -421,8 +415,7 @@ is_process_group_leader(struct team *team)
} }
/** You must hold the team lock when calling this function. */ /*! You must hold the team lock when calling this function. */
static void static void
insert_group_into_session(struct process_session *session, struct process_group *group) insert_group_into_session(struct process_session *session, struct process_group *group)
{ {
@ -435,8 +428,7 @@ insert_group_into_session(struct process_session *session, struct process_group
} }
/** You must hold the team lock when calling this function. */ /*! You must hold the team lock when calling this function. */
static void static void
insert_team_into_group(struct process_group *group, struct team *team) insert_team_into_group(struct process_group *group, struct team *team)
{ {
@ -449,11 +441,10 @@ insert_team_into_group(struct process_group *group, struct team *team)
} }
/** Removes a group from a session, and puts the session object /*! Removes a group from a session, and puts the session object
* back into the session cache, if it's not used anymore. back into the session cache, if it's not used anymore.
* You must hold the team lock when calling this function. You must hold the team lock when calling this function.
*/ */
static void static void
remove_group_from_session(struct process_group *group) remove_group_from_session(struct process_group *group)
{ {
@ -472,18 +463,15 @@ remove_group_from_session(struct process_group *group)
} }
/*! Removes the team from the group. If that group becomes therefore
unused, it will set \a _freeGroup to point to the group - otherwise
it will be \c NULL.
It cannot be freed here because this function has to be called
with having the team lock held.
\param team the team that'll be removed from it's group
/** Removes the team from the group. If that group becomes therefore \param _freeGroup points to the group to be freed or NULL
* unused, it will set \a _freeGroup to point to the group - otherwise */
* it will be \c NULL.
* It cannot be freed here because this function has to be called
* with having the team lock held.
*
* \param team the team that'll be removed from it's group
* \param _freeGroup points to the group to be freed or NULL
*/
static void static void
remove_team_from_group(struct team *team, struct process_group **_freeGroup) remove_team_from_group(struct team *team, struct process_group **_freeGroup)
{ {
@ -865,7 +853,7 @@ team_create_thread_start(void *args)
return err; return err;
} }
TRACE(("team_create_thread_start: loaded elf. entry = 0x%lx\n", entry)); TRACE(("team_create_thread_start: loaded elf. entry = %#lx\n", entry));
team->state = TEAM_STATE_NORMAL; team->state = TEAM_STATE_NORMAL;
@ -875,10 +863,9 @@ team_create_thread_start(void *args)
} }
/** The BeOS kernel exports a function with this name, but most probably with /*! The BeOS kernel exports a function with this name, but most probably with
* different parameters; we should not make it public. different parameters; we should not make it public.
*/ */
static thread_id static thread_id
load_image_etc(int32 argCount, char * const *args, int32 envCount, load_image_etc(int32 argCount, char * const *args, int32 envCount,
char * const *env, int32 priority, uint32 flags, char * const *env, int32 priority, uint32 flags,
@ -1023,12 +1010,11 @@ err1:
} }
/** Almost shuts down the current team and loads a new image into it. /*! Almost shuts down the current team and loads a new image into it.
* If successful, this function does not return and will takeover ownership of If successful, this function does not return and will takeover ownership of
* the arguments provided. the arguments provided.
* This function may only be called from user space. This function may only be called from user space.
*/ */
static status_t static status_t
exec_team(const char *path, int32 argCount, char * const *args, exec_team(const char *path, int32 argCount, char * const *args,
int32 envCount, char * const *env) int32 envCount, char * const *env)
@ -1041,7 +1027,7 @@ exec_team(const char *path, int32 argCount, char * const *args,
struct thread *thread; struct thread *thread;
thread_id nubThreadID = -1; thread_id nubThreadID = -1;
TRACE(("exec_team(path = \"%s\", argc = %ld, envCount = %ld): team %lx\n", TRACE(("exec_team(path = \"%s\", argc = %ld, envCount = %ld): team %ld\n",
args[0], argCount, envCount, team->id)); args[0], argCount, envCount, team->id));
// switching the kernel at run time is probably not a good idea :) // switching the kernel at run time is probably not a good idea :)
@ -1128,12 +1114,11 @@ exec_team(const char *path, int32 argCount, char * const *args,
} }
/** This is the first function to be called from the newly created /*! This is the first function to be called from the newly created
* main child thread. main child thread.
* It will fill in everything what's left to do from fork_arg, and It will fill in everything what's left to do from fork_arg, and
* return from the parent's fork() syscall to the child. return from the parent's fork() syscall to the child.
*/ */
static int32 static int32
fork_team_thread_start(void *_args) fork_team_thread_start(void *_args)
{ {
@ -1175,7 +1160,7 @@ fork_team(void)
status_t status; status_t status;
int32 cookie; int32 cookie;
TRACE(("fork_team(): team %lx\n", parentTeam->id)); TRACE(("fork_team(): team %ld\n", parentTeam->id));
if (parentTeam == team_get_kernel_team()) if (parentTeam == team_get_kernel_team())
return B_NOT_ALLOWED; return B_NOT_ALLOWED;
@ -1288,10 +1273,10 @@ err1:
} }
/** Returns if the specified \a team has any children belonging to the specified \a group. /*! Returns if the specified \a team has any children belonging to the
* Must be called with the team lock held. specified \a group.
*/ Must be called with the team lock held.
*/
static bool static bool
has_children_in_group(struct team *parent, pid_t groupID) has_children_in_group(struct team *parent, pid_t groupID)
{ {
@ -1504,11 +1489,10 @@ wait_for_child(pid_t child, uint32 flags, int32 *_reason,
} }
/** Fills the team_info structure with information from the specified /*! Fills the team_info structure with information from the specified
* team. team.
* The team lock must be held when called. The team lock must be held when called.
*/ */
static status_t static status_t
fill_team_info(struct team *team, team_info *info, size_t size) fill_team_info(struct team *team, team_info *info, size_t size)
{ {
@ -1675,9 +1659,7 @@ team_get_death_entry(struct team *team, thread_id child, bool* _deleteEntry)
} }
/** Quick check to see if we have a valid team ID. /*! Quick check to see if we have a valid team ID. */
*/
bool bool
team_is_valid(team_id id) team_is_valid(team_id id)
{ {
@ -1709,10 +1691,9 @@ team_get_team_struct_locked(team_id id)
} }
/** This searches the session of the team for the specified group ID. /*! This searches the session of the team for the specified group ID.
* You must hold the team lock when you call this function. You must hold the team lock when you call this function.
*/ */
struct process_group * struct process_group *
team_get_process_group_locked(struct process_session *session, pid_t id) team_get_process_group_locked(struct process_session *session, pid_t id)
{ {
@ -2126,11 +2107,10 @@ team_set_job_control_state(struct team* team, job_control_state newState,
} }
/** Adds a hook to the team that is called as soon as this /*! Adds a hook to the team that is called as soon as this
* team goes away. team goes away.
* This call might get public in the future. This call might get public in the future.
*/ */
status_t status_t
start_watching_team(team_id teamID, void (*hook)(team_id, void *), void *data) start_watching_team(team_id teamID, void (*hook)(team_id, void *), void *data)
{ {