/* Copyright (C) 2005 David Decotigny This program 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 of the License, or (at your option) any later version. 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. 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-1307, USA. */ #include #include #include #include #include #include #include "process.h" #define SOS_PROCESS_MAX_NAMELEN 32 /** * Definition of a process in SOS. A process is basically the * collection of all the resources requested by a user program. The * threads are one of these resources, the mm_context is one other * example of such resources. */ struct sos_process { char name[SOS_PROCESS_MAX_NAMELEN]; /** First important resource: the MMU translation tables' configuration */ struct sos_mm_context *mm_context; /** Second important resource: the CPU execution contexts, aka the threads executing in the context of this process. */ struct sos_thread *thread_list; sos_count_t nb_threads; /** Reference counter, including threads */ sos_count_t ref_cnt; struct sos_process *prev, *next; }; /** The list of processes in the system */ static struct sos_process *process_list = NULL; /** The cache for the sos_process structures */ struct sos_kslab_cache *cache_struct_process; /** * Helper function for debugging purposes */ void sos_process_dumplist() { struct sos_thread * cur_thr = sos_thread_get_current(); struct sos_process * proc; int nb_procs; sos_bochs_printf("\n"); list_foreach(process_list, proc, nb_procs) { struct sos_thread * thr; int nb_thrs; sos_bochs_printf(" proc@%p: '%s', %d threads, %d refs\n", proc, proc->name?proc->name:"(none)", proc->nb_threads, proc->ref_cnt); list_foreach_forward_named(proc->thread_list, thr, nb_thrs, prev_in_process, next_in_process) { if (thr == cur_thr) sos_bochs_printf(" thr@%p: [CURRENT]\n", thr); else sos_bochs_printf(" thr@%p: %cstate=%d eip=%p\n", thr, sos_cpu_context_is_in_user_mode(thr->cpu_state)?'u':'k', thr->state, (void*)sos_cpu_context_get_PC(thr->cpu_state)); } } sos_bochs_printf(" ======= %d processes =======\n", nb_procs); sos_bochs_printf("\n"); } sos_ret_t sos_process_subsystem_setup() { /* Create the cache for the process structures */ cache_struct_process = sos_kmem_cache_create("struct_process", sizeof(struct sos_process), 3, 0, SOS_KSLAB_CREATE_MAP | SOS_KSLAB_CREATE_ZERO); if (! cache_struct_process) return -SOS_ENOMEM; return SOS_OK; } struct sos_process *sos_process_create_empty(const char *name) { sos_ui32_t flags; struct sos_process *proc; proc = (struct sos_process*) sos_kmem_cache_alloc(cache_struct_process, 0); if (! proc) return NULL; /* proc is already filled with 0 (cache has SOS_KSLAB_CREATE_ZERO flag) */ /* Initialize a new mm_context */ proc->mm_context = sos_mm_context_create(); if (NULL == proc->mm_context) { /* Error */ sos_kmem_cache_free((sos_vaddr_t)proc); return NULL; } if (!name) { name = "[UNNAMED]"; } strzcpy(proc->name, name, SOS_PROCESS_MAX_NAMELEN); /* Add it to the global list of processes */ sos_disable_IRQs(flags); list_add_tail(process_list, proc); sos_restore_IRQs(flags); /* Mark the process as referenced */ proc->ref_cnt = 1; return proc; } inline sos_ret_t sos_process_ref(struct sos_process *proc) { sos_ui32_t flags; sos_disable_IRQs(flags); proc->ref_cnt ++; sos_restore_IRQs(flags); return SOS_OK; } sos_count_t sos_process_get_nb_threads(const struct sos_process *proc) { sos_count_t retval; sos_ui32_t flags; sos_disable_IRQs(flags); retval = proc->nb_threads; sos_restore_IRQs(flags); return retval; } struct sos_mm_context * sos_process_get_mm_context(const struct sos_process *proc) { return proc->mm_context; } /* *************************************************** * Restricted functions */ sos_ret_t sos_process_register_thread(struct sos_process *in_proc, struct sos_thread *thr) { sos_ui32_t flags; /* The process is assumed to be referenced by somebody */ SOS_ASSERT_FATAL(in_proc->ref_cnt > 0); /* Only threads that are being created are allowed to be attached to a process */ SOS_ASSERT_FATAL(thr->state == SOS_THR_CREATED); /* Update the list of the threads in the process */ thr->process = in_proc; /* Increment the reference count for the process */ sos_process_ref(in_proc); /* Add the thread to the process thread's list */ sos_disable_IRQs(flags); list_add_tail_named(in_proc->thread_list, thr, prev_in_process, next_in_process); in_proc->nb_threads ++; sos_restore_IRQs(flags); return SOS_OK; } /** The function responsible for releasing the resources held by the process. */ sos_ret_t sos_process_unref(struct sos_process *proc) { sos_ui32_t flags; sos_ret_t retval; SOS_ASSERT_FATAL(proc->ref_cnt > 0); sos_disable_IRQs(flags); proc->ref_cnt --; if (proc->ref_cnt > 0) { sos_restore_IRQs(flags); return -SOS_EBUSY; } list_delete(process_list, proc); sos_restore_IRQs(flags); /* First: release the mm_context */ retval = sos_mm_context_unref(proc->mm_context); SOS_ASSERT_FATAL(SOS_OK == retval); /* Free the process structure */ sos_kmem_cache_free((sos_vaddr_t)proc); return SOS_OK; } sos_ret_t sos_process_unregister_thread(struct sos_thread *thr) { sos_ui32_t flags; struct sos_process * in_proc = thr->process; SOS_ASSERT_FATAL(thr->state == SOS_THR_ZOMBIE); /* Update the list of the threads in the process */ thr->process = NULL; sos_disable_IRQs(flags); list_delete_named(in_proc->thread_list, thr, prev_in_process, next_in_process); SOS_ASSERT_FATAL(in_proc->nb_threads > 0); in_proc->nb_threads --; sos_restore_IRQs(flags); /* Unreference the process */ sos_process_unref(in_proc); return SOS_OK; } sos_ret_t sos_process_set_name(struct sos_process * proc, const char * new_name) { strzcpy(proc->name, new_name, SOS_PROCESS_MAX_NAMELEN); return SOS_OK; }