281 lines
6.7 KiB
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;
|
|
}
|