sos-code-article7/sos/process.c

281 lines
6.7 KiB
C

/* 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 <sos/assert.h>
#include <sos/list.h>
#include <sos/kmem_slab.h>
#include <hwcore/irq.h>
#include <drivers/bochs.h>
#include <hwcore/mm_context.h>
#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("<ps>\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("</ps>\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;
}