haiku/src/kernel/core/image.c
Axel Dörfler 429578fb0b Team/image stuff now uses lists instead of kqueues.
The kernel_daemon now utilizes the updated list API.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@2567 a95241bf-73f2-0310-859d-f6bbb57e9c96
2003-01-26 23:31:38 +00:00

266 lines
4.8 KiB
C

/* User Runtime Loader support in the kernel
**
** Copyright 2003, Axel Dörfler, axeld@pinc-software.de. All rights reserved.
** Distributed under the terms of the OpenBeOS License.
*/
#include <KernelExport.h>
#include <kimage.h>
#include <thread_types.h>
#include <thread.h>
#include <malloc.h>
#include <string.h>
// ToDo: register kernel images as well
struct image {
struct image *next;
struct image *prev;
image_info info;
};
static image_id gNextImageID = 1;
/** Registers an image with the specified team.
*/
image_id
register_image(team_id teamID, image_info *_info, size_t size)
{
image_id id = atomic_add(&gNextImageID, 1);
struct image *image;
struct team *team;
cpu_status state;
image = malloc(sizeof(image_info));
if (image == NULL)
return B_NO_MEMORY;
memcpy(&image->info, _info, sizeof(image_info));
state = disable_interrupts();
GRAB_TEAM_LOCK();
team = team_get_team_struct_locked(teamID);
if (team) {
image->info.id = id;
list_add_item(&team->image_list, image);
}
RELEASE_TEAM_LOCK();
restore_interrupts(state);
dprintf("register_image(team = %ld, image id = %ld, image = %p\n", teamID, id, image);
return id;
}
/** Unregisters an image from the specified team.
*/
status_t
unregister_image(team_id teamID, image_id id)
{
status_t status = B_ENTRY_NOT_FOUND;
struct team *team;
cpu_status state;
state = disable_interrupts();
GRAB_TEAM_LOCK();
team = team_get_team_struct_locked(teamID);
if (team) {
struct image *image = NULL;
while ((image = list_get_next_item(&team->image_list, image)) != NULL) {
if (image->info.id == id) {
list_remove_link(image);
free(image);
status = B_OK;
break;
}
}
}
RELEASE_TEAM_LOCK();
restore_interrupts(state);
return status;
}
/** Counts the registered images from the specified team.
* The team lock must be hold when you call this function.
*/
int32
count_images(struct team *team)
{
struct image *image = NULL;
int32 count = 0;
while ((image = list_get_next_item(&team->image_list, image)) != NULL) {
count++;
}
return count;
}
/** Removes all images from the specified team. Must only be called
* with the team lock hold or a team that has already been removed
* from the list (in thread_exit()).
*/
status_t
remove_images(struct team *team)
{
struct image *image;
ASSERT(team != NULL);
while ((image = list_remove_head_item(&team->image_list)) != NULL) {
free(image);
}
return B_OK;
}
status_t
_get_image_info(image_id id, image_info *info, size_t size)
{
status_t status = B_ENTRY_NOT_FOUND;
struct team *team;
cpu_status state;
state = disable_interrupts();
GRAB_TEAM_LOCK();
team = thread_get_current_thread()->team;
if (team) {
struct image *image = NULL;
while ((image = list_get_next_item(&team->image_list, image)) != NULL) {
if (image->info.id == id) {
memcpy(info, &image->info, size);
status = B_OK;
break;
}
}
}
RELEASE_TEAM_LOCK();
restore_interrupts(state);
return status;
}
status_t
_get_next_image_info(team_id teamID, int32 *cookie, image_info *info, size_t size)
{
status_t status = B_ENTRY_NOT_FOUND;
struct team *team;
cpu_status state;
state = disable_interrupts();
GRAB_TEAM_LOCK();
team = team_get_team_struct_locked(teamID);
if (team) {
struct image *image = NULL;
int32 count = 0;
while ((image = list_get_next_item(&team->image_list, image)) != NULL) {
if (count == *cookie) {
memcpy(info, &image->info, size);
status = B_OK;
(*cookie)++;
break;
}
count++;
}
} else
status = B_BAD_TEAM_ID;
RELEASE_TEAM_LOCK();
restore_interrupts(state);
return status;
}
// #pragma mark -
// Functions exported for the user space
status_t
user_unregister_image(image_id id)
{
return unregister_image(team_get_current_team_id(), id);
}
image_id
user_register_image(image_info *userInfo, size_t size)
{
image_info info;
if (size != sizeof(image_info))
return B_BAD_VALUE;
if (!CHECK_USER_ADDRESS(userInfo)
|| user_memcpy(&info, userInfo, size) < B_OK)
return B_BAD_ADDRESS;
return register_image(team_get_current_team_id(), &info, size);
}
status_t
user_get_image_info(image_id id, image_info *userInfo, size_t size)
{
image_info info;
status_t status;
if (size != sizeof(image_info))
return B_BAD_VALUE;
if (!CHECK_USER_ADDRESS(userInfo))
return B_BAD_ADDRESS;
status = _get_image_info(id, &info, size);
if (user_memcpy(userInfo, &info, size) < B_OK)
return B_BAD_ADDRESS;
return status;
}
status_t
user_get_next_image_info(team_id team, int32 *_cookie, image_info *userInfo, size_t size)
{
image_info info;
status_t status;
if (size != sizeof(image_info))
return B_BAD_VALUE;
if (!CHECK_USER_ADDRESS(userInfo) || !CHECK_USER_ADDRESS(_cookie))
return B_BAD_ADDRESS;
status = _get_next_image_info(team, _cookie, &info, size);
if (user_memcpy(userInfo, &info, size) < B_OK)
return B_BAD_ADDRESS;
return status;
}