Index: task/ia32-cmain.c =================================================================== RCS file: /cvsroot/hurd/hurd-l4/task/ia32-cmain.c,v retrieving revision 1.2 diff -u -r1.2 ia32-cmain.c --- task/ia32-cmain.c 26 Apr 2004 21:21:22 -0000 1.2 +++ task/ia32-cmain.c 9 Aug 2004 19:51:44 -0000 @@ -30,7 +30,7 @@ #include #include -#include "task.h" +#include "task-internal.h" #include Index: task/task.c =================================================================== RCS file: /cvsroot/hurd/hurd-l4/task/task.c,v retrieving revision 1.2 diff -u -r1.2 task.c --- task/task.c 26 Apr 2004 21:21:22 -0000 1.2 +++ task/task.c 9 Aug 2004 19:51:44 -0000 @@ -1,15 +1,13 @@ /* Main function for the task server. - Copyright (C) 2004 Free Software Foundation, Inc. - Written by Marcus Brinkmann. + parts Copyright (C) Free Software Foundation + Copyright (C) 2004 Bas Wijnen + Written by Bas Wijnen + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. - This file is part of the GNU Hurd. - - The GNU Hurd is free software; you can redistribute it and/or - modify it under the terms of the GNU Lesser General Public - License as published by the Free Software Foundation; either - version 2.1 of the License, or (at your option) any later version. - - The GNU Hurd is distributed in the hope that it will be useful, + This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. @@ -26,6 +24,8 @@ #include #include +#include "wortel/wortel.h" +#include "task-internal.h" #include "task.h" @@ -57,21 +57,420 @@ return l4_min_page_size (); } - -int -main (int argc, char *argv[]) + +/* types */ + +/* a list of threads, used by taskinfo */ +struct threadlist { + struct threadlist *next; + l4_thread_id_t id; +}; + +/* A taskinfo cap lets you be notified of task deaths. */ +struct taskinfo +{ + /* This must be the first member. */ + struct hurd_cap_obj obj; + + struct taskinfo *next, *prev; + + /* A task is simply a list of threads. */ + struct threadlist *threads; + int id; +}; + +/* There are 3 taskcontrol objects, one with much power (=2), one with normal + * power (=1) and one without power (=root capability). */ +struct taskcontrol +{ + /* This must be the first member. */ + struct hurd_cap_obj obj; + + /* Capabilities to the power object allow killing other tasks. */ + int power; +}; + +/* variables which are used by many functions */ +static l4_thread_id_t wortel_thread_id; +static l4_word_t minimum_thread_no, maximum_thread_no; +static struct hurd_cap_class taskinfo_class, taskcontrol_class; +static hurd_cap_bucket_t bucket; +static struct taskcontrol powercontrol, normalcontrol, rootcontrol; + + +/* FIXME: using arbitrarily limited static memory tables. */ +#define MAX_THREAD 1000 +#define MAX_TASK 500 +struct threadlist threads[MAX_THREAD], *unused_threads; +struct taskinfo tasks[MAX_TASK], *unused_tasks, *first_task; + +typedef int mem_task_t; + +void mem_init () +{ + int i; + for (i = 0; i < MAX_THREAD; ++i) + { + threads[i].next = &threads[i + 1]; + threads[i].id = -1; + } + threads[MAX_THREAD - 1].next = NULL; + unused_threads = &threads[0]; + + for (i = 0; i < MAX_TASK; ++i) + { + tasks[i].next = tasks + i + 1; + tasks[i].prev = tasks + i - 1; + tasks[i].id = -1; + } + tasks[MAX_TASK - 1].next = NULL; + tasks[0].prev = NULL; + unused_tasks = &tasks[0]; + first_task = NULL; +} + +struct taskinfo *mem_get_task (mem_task_t task_id) +{ + if (task_id < 0 || task_id >= MAX_TASK) + return NULL; + return &tasks[task_id]; +} + +/* FIXME: do locking. */ +mem_task_t mem_add_task () +{ + error_t err; + struct taskinfo *task; + + /* lock */ + if (unused_tasks == NULL) + panic ("no more tasks available"); + task = unused_tasks; + unused_tasks = unused_tasks->next; + err = hurd_cap_class_alloc (&taskinfo_class, (hurd_cap_obj_t *)task); + if (err) + panic ("unable to allocate new taskinfo capability object"); + hurd_cap_obj_unlock (&task->obj); + task->id = task - &tasks[0]; + task->next = first_task; + task->prev = NULL; + first_task->prev = task; + first_task = task; + /* unlock */ + return task->id; +} + +/* FIXME: do locking. */ +void mem_add_thread (mem_task_t task, l4_word_t thread_id) +{ + struct threadlist *thread; + + /* lock tasks */ + if (tasks[task].id == -1) + panic ("invalid task"); + /* lock tasks[task] */ + /* unlock tasks */ + + /* lock threads */ + if (unused_threads == NULL) + panic ("no more threads available"); + thread = unused_threads; + unused_threads = unused_threads->next; + /* unlock threads */ + + thread->next = tasks[task].threads; + tasks[task].threads = thread; + thread->id = thread_id; + /* unlock tasks[task] */ +} + + +/* set up the memory with initial capabilities */ +static hurd_cap_handle_t setup_memory () +{ + l4_msg_t msg; + l4_msg_tag_t tag; + l4_word_t wortel_threads, physmem_threads, task_threads; + mem_task_t wortel_task, physmem_task, task_task; + l4_word_t i; + hurd_cap_handle_t cap; + error_t err; + + /* get information about currently reserved threads. */ + tag = wortel_task_get_info (&msg); + + if (l4_typed_words (tag) != 0 || l4_untyped_words (tag) < 4) + panic ("invalid initial message from wortel (1st check)"); + + minimum_thread_no = l4_msg_word (msg, 0); + maximum_thread_no = l4_msg_word (msg, 1); + + wortel_threads = l4_msg_word (msg, 2); + physmem_threads = l4_msg_word (msg, 3); + task_threads = l4_msg_word (msg, 4); + if (physmem_threads < 1 || task_threads < 1 || wortel_threads < 1 || + l4_untyped_words (tag) != 4 + wortel_threads + physmem_threads + + task_threads) + panic ("invalid initial message from wortel (2nd check)"); + + if (minimum_thread_no + wortel_threads + physmem_threads + task_threads + >= maximum_thread_no) + panic ("not enough threads to manage"); + + mem_init (); + + wortel_task = mem_add_task (); + for (i = 0; i < wortel_threads; ++i) + mem_add_thread (wortel_task, l4_msg_word (msg, 5 + i)); + physmem_task = mem_add_task (); + for (i = 0; i < physmem_threads; ++i) + mem_add_thread (physmem_task, l4_msg_word (msg, 5 + wortel_threads + i)); + task_task = mem_add_task (); + for (i = 0; i < task_threads; ++i) + mem_add_thread (task_task, l4_msg_word (msg, 5 + wortel_threads + + physmem_threads + i)); + /* create the three taskcontrol capability objects. */ + err = hurd_cap_class_alloc (&taskcontrol_class, + (hurd_cap_obj_t *) &powercontrol); + if (err) + panic ("unable to allocate power control capability object"); + hurd_cap_obj_unlock (&powercontrol.obj); + + err = hurd_cap_class_alloc (&taskcontrol_class, + (hurd_cap_obj_t *) &normalcontrol); + if (err) + panic ("unable to allocate control capability object"); + hurd_cap_obj_unlock (&normalcontrol.obj); + err = hurd_cap_class_alloc (&taskcontrol_class, + (hurd_cap_obj_t *) &rootcontrol); + if (err) + panic ("unable to allocate root control capability object"); + hurd_cap_obj_unlock (&rootcontrol.obj); + /* give power taskcontrol capability to wortel. */ + err = hurd_cap_bucket_inject (bucket, &powercontrol.obj, wortel_thread_id, + &cap); + if (err) + panic ("hurd_cap_bucket_inject: %i\n", err); + + hurd_cap_obj_lock (&powercontrol.obj); + hurd_cap_obj_drop (&powercontrol.obj); + /* don't drop the reference to normalcontrol, because powercontrol can give + * out capabilities for it. */ + return cap; +} + + +/* tasks must be locked when this function is called. It will not be + * unlocked. */ +static void task_exit (struct taskinfo *task) { + if (task->id == -1) + /* already killed. */ + return; + /* FIXME: kill all threads and address space of task (via wortel.) */ + /* FIXME: notify others. For now, the struct is dectivated, but not put + * back into the list of available tasks. */ + if (task->prev) + task->prev->next = task->next; + else + first_task = task->next; + if (task->next) + task->next->prev = task->prev; + task->id = -1; +} + + +static l4_thread_id_t +thread_create () +{ + /* FIXME: create thread via wortel. */ + return 1; +} + +static error_t taskinfo_demuxer (hurd_cap_rpc_context_t ctx) +{ + /* taskinfo does not have any methods. */ + return 1; +} + +static error_t taskcontrol_demuxer (hurd_cap_rpc_context_t ctx) +{ + struct taskcontrol *obj = (struct taskcontrol *)ctx->obj; + hurd_cap_handle_t cap; error_t err; - l4_thread_id_t server_thread; - hurd_cap_bucket_t bucket; - pthread_t manager; + struct taskinfo *task; + l4_msg_tag_t tag = l4_niltag; - output_debug = 1; + /* normally, reply with same label to indicate success. */ + l4_set_msg_label (&tag, l4_msg_label (ctx->msg)); + l4_set_msg_msg_tag (ctx->msg, tag); + + if (obj->power >= 2) + switch (l4_msg_label (ctx->msg)) + { + case HURD_TASK_GET_NOPOWER: + err = hurd_cap_bucket_inject (bucket, &normalcontrol.obj, ctx->sender, + &cap); + if (err) + return err; + l4_msg_append_word (ctx->msg, cap); + return 0; + case HURD_TASK_KILL: + /* lock tasks */ + task = mem_get_task (l4_msg_word (ctx->msg, 2)); + if (task == NULL) + return 1; + task_exit (task); + /* unlock tasks */ + /* FIXME: If the task has just been killed, this will fail. This is + * a problem, because the task id could have been reused, since we + * released our lock before replying (which happens after return.) */ + return 0; + } + if (obj->power >= 1) + { + switch (l4_msg_label (ctx->msg)) + { + case HURD_TASK_CREATE: + /* FIXME */ + return 1; + case HURD_TASK_NEW_THREAD: + /* FIXME */ + return 1; + default: + return 1; + } + } + switch (l4_msg_label (ctx->msg)) + { + case HURD_TASK_EXIT: + /* lock tasks */ + task_exit (mem_get_task (ctx->sender)); + /* unlock tasks */ + return 0; + case HURD_TASK_KILL_THREAD: + /* FIXME */ + return 1; + case HURD_TASK_GET_INFO: + if (l4_untyped_words (l4_msg_msg_tag (ctx->msg)) < 2) + return 1; + /* lock tasks */ + task = mem_get_task (l4_msg_word (ctx->msg, 1)); + if (task == NULL) + { + /* unlock tasks */ + return 1; + } + /* lock task */ + /* unlock tasks */ + err = hurd_cap_bucket_inject (bucket, &task->obj, ctx->sender, &cap); + if (err) + panic ("unable to inject taskinfo capability"); + l4_msg_append_word (ctx->msg, cap); + return 0; + } +} + + +void task_reinit (hurd_cap_class_t class, hurd_cap_obj_t obj) +{ + struct taskinfo *task = (struct taskinfo *)obj; + /* lock tasks */ + task_exit (task); + /* unlock tasks */ +} + + +/* set up capability server. Don't start any threads yet, because the + * memory to store information about the has not been set up. */ +static void setup_cap_server () +{ + error_t err; + + err = hurd_cap_class_init (&taskinfo_class, sizeof (struct taskinfo), + __alignof__ (struct taskinfo), NULL, NULL, + task_reinit, NULL, taskinfo_demuxer); + if (err) + panic ("taskinfo class_init: %i", err); + + err = hurd_cap_class_init (&taskcontrol_class, sizeof (struct taskcontrol), + __alignof__ (struct taskcontrol), NULL, NULL, + NULL, NULL, taskcontrol_demuxer); + if (err) + panic ("taskcontrol class_init: %i", err); + + err = hurd_cap_bucket_create (&bucket); + if (err) + panic ("bucket_create: %i", err); +} + +void * +task_server (void *arg) +{ + hurd_cap_bucket_t bucket = (hurd_cap_bucket_t) arg; + error_t err; + + err = hurd_cap_bucket_manage_mt (bucket, (hurd_cap_obj_t)&rootcontrol, 0, 0); + if (err) + debug ("bucket_manage_mt failed: %i\n", err); + + panic ("bucket_manage_mt returned!"); +} + +static void start_cap_server () +{ +#define NUM_WORKER_THREADS 2 + l4_thread_id_t tid; + pthread_t thread, manager; + error_t err; + unsigned i; + + err = pthread_create (&thread, 0, 0, 0); + if (err) + panic ("pthread_create: %i", err); + + for (i = 0; i < NUM_WORKER_THREADS; ++i) + { + tid = thread_create (); + pthread_pool_add_np (tid); + } + + tid = thread_create (); + err = pthread_create_from_l4_tid_np (&manager, NULL, tid, task_server, + bucket); + if (err) + panic ("pthread_create_from_l4_tid_np: %i", err); + pthread_detach (manager); +} + +int main (int argc, char *argv[]) +{ + error_t err; + hurd_cap_handle_t powercontrol_cap; debug ("%s " PACKAGE_VERSION "\n", program_name); + /* FIXME: Hard coded thread ID. */ + wortel_thread_id = l4_global_id (l4_thread_user_base () + 2, 1); + + /* Set up capability server */ + setup_cap_server (); + + /* Set up memory according to already running tasks. */ + /* This also fills {minimum,maximum}_thread_no. */ + powercontrol_cap = setup_memory (); + + /* Start up everything. */ + start_cap_server (); + + /* The task server is up and running. Tell wortel about it by giving it a + * taskcontrol capability. System boot continues after that. */ + err = wortel_task_send_control (powercontrol_cap); + if (err) + panic ("unable to send task control capability"); + + /* Don't do anything anymore. I don't understand why this thread isn't + * used for something. This was just copied from physmem. */ while (1) l4_sleep (L4_NEVER); - - return 0; } Index: task/task.h =================================================================== RCS file: /cvsroot/hurd/hurd-l4/task/task.h,v retrieving revision 1.1 diff -u -r1.1 task.h --- task/task.h 15 Apr 2004 11:24:00 -0000 1.1 +++ task/task.h 9 Aug 2004 19:51:44 -0000 @@ -1,42 +1,38 @@ -/* task.h - Generic definitions. - Copyright (C) 2004 Free Software Foundation, Inc. - Written by Marcus Brinkmann. - - This file is part of the GNU Hurd. - - The GNU Hurd is free software; you can redistribute it and/or - modify it under the terms of the GNU General Public License as - published by the Free Software Foundation; either version 2, or (at - your option) any later version. +/* Task server external header, for programs which use its capabilitie system. + Copyright (C) 2004 Bas Wijnen + Written by Bas Wijnen + + This program is free software; you can redistribute it and/or + modify it under the terms of the GNU General Public License + version 2 as published by the Free Software Foundation. - The GNU Hurd is distributed in the hope that it will be useful, but - WITHOUT ANY WARRANTY; without even the implied warranty of + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - General Public License for more details. + Lesser General Public License for more details. - You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software - Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111, USA. */ + You should have received a copy of the GNU Lesser General Public + License along with the GNU C Library; if not, write to the Free + Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA + 02111-1307 USA. */ -#include +#ifndef _TASK_H +#define _TASK_H -#include -#include +/* Reply values. To indicate success, the request is returned. */ +#define HURD_TASK_ERROR 0x00 -#include "output.h" +/* Requests for the root capability object. */ +#define HURD_TASK_EXIT 0x10 +#define HURD_TASK_KILL_THREAD 0x11 +#define HURD_TASK_GET_INFO 0x12 - -/* The program name. */ -extern char program_name[]; +/* Requests for the power control capability object. */ +#define HURD_TASK_GET_NOPOWER 0x20 +#define HURD_TASK_KILL 0x21 -#define BUG_ADDRESS "" +/* Requests for any control capability object. */ +#define HURD_TASK_CREATE 0x30 +#define HURD_TASK_NEW_THREAD 0x31 -int main (int argc, char *argv[]); - - -/* The following function must be defined by the architecture - dependent code. */ - -/* Switch execution transparently to thread TO. The thread FROM, - which must be the current thread, will be halted. */ -void switch_thread (l4_thread_id_t from, l4_thread_id_t to); +#endif Index: wortel/wortel.h =================================================================== RCS file: /cvsroot/hurd/hurd-l4/wortel/wortel.h,v retrieving revision 1.12 diff -u -r1.12 wortel.h --- wortel/wortel.h 26 Apr 2004 21:15:21 -0000 1.12 +++ wortel/wortel.h 9 Aug 2004 19:51:52 -0000 @@ -56,6 +56,9 @@ #define WORTEL_MSG_GET_THREADS 67 #define WORTEL_MSG_GET_TASK_CAP 68 +#define WORTEL_MSG_TASK_GET_INFO 96 +#define WORTEL_MSG_TASK_SEND_CONTROL 97 + #define _WORTEL_LABEL(id) \ (((id) << WORTEL_MSG_CAP_ID_BITS) \ | (wortel_cap_id & ((1 << WORTEL_MSG_CAP_ID_BITS) - 1))) @@ -341,4 +344,43 @@ return task; } + +/* Get information about running tasks. */ +static inline l4_msg_tag_t +__attribute__((always_inline)) +wortel_task_get_info (l4_msg_t *msg) +{ + l4_msg_tag_t tag; + + l4_accept (L4_UNTYPED_WORDS_ACCEPTOR); + + tag = l4_niltag; + l4_msg_tag_set_label (&tag, _WORTEL_LABEL (WORTEL_MSG_TASK_GET_INFO)); + l4_set_msg_tag (tag); + tag = l4_call (wortel_thread_id); + + if (!l4_ipc_failed (tag)) + l4_msg_store (tag, *msg); + return tag; +} + + +/* Give power control capability to wortel. */ +static inline error_t +__attribute__((always_inline)) +wortel_task_send_control (hurd_cap_handle_t cap) +{ + l4_msg_tag_t tag; + + tag = l4_niltag; + l4_msg_tag_set_label (&tag, _WORTEL_LABEL (WORTEL_MSG_TASK_SEND_CONTROL)); + l4_msg_tag_set_untyped_words (&tag, 1); + l4_set_msg_tag (tag); + l4_load_mr (1, cap); + tag = l4_reply (wortel_thread_id); + if (l4_ipc_failed (tag)) + return 1; + return 0; +} + #endif /* _WORTEL_USER_H */