iPXE
process.c
Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License as
00006  * published by the Free Software Foundation; either version 2 of the
00007  * License, or any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful, but
00010  * WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00012  * General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software
00016  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
00017  * 02110-1301, USA.
00018  *
00019  * You can also choose to distribute this program under the terms of
00020  * the Unmodified Binary Distribution Licence (as given in the file
00021  * COPYING.UBDL), provided that you have satisfied its requirements.
00022  */
00023 
00024 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
00025 
00026 #include <ipxe/list.h>
00027 #include <ipxe/init.h>
00028 #include <ipxe/process.h>
00029 
00030 /** @file
00031  *
00032  * Processes
00033  *
00034  * We implement a trivial form of cooperative multitasking, in which
00035  * all processes share a single stack and address space.
00036  */
00037 
00038 /** Process run queue */
00039 static LIST_HEAD ( run_queue );
00040 
00041 /**
00042  * Get pointer to object containing process
00043  *
00044  * @v process           Process
00045  * @ret object          Containing object
00046  */
00047 void * process_object ( struct process *process ) {
00048         return ( ( ( void * ) process ) - process->desc->offset );
00049 }
00050 
00051 /**
00052  * Add process to process list
00053  *
00054  * @v process           Process
00055  *
00056  * It is safe to call process_add() multiple times; further calls will
00057  * have no effect.
00058  */
00059 void process_add ( struct process *process ) {
00060         if ( ! process_running ( process ) ) {
00061                 DBGC ( PROC_COL ( process ), "PROCESS " PROC_FMT
00062                        " starting\n", PROC_DBG ( process ) );
00063                 ref_get ( process->refcnt );
00064                 list_add_tail ( &process->list, &run_queue );
00065         } else {
00066                 DBGC ( PROC_COL ( process ), "PROCESS " PROC_FMT
00067                        " already started\n", PROC_DBG ( process ) );
00068         }
00069 }
00070 
00071 /**
00072  * Remove process from process list
00073  *
00074  * @v process           Process
00075  *
00076  * It is safe to call process_del() multiple times; further calls will
00077  * have no effect.
00078  */
00079 void process_del ( struct process *process ) {
00080         if ( process_running ( process ) ) {
00081                 DBGC ( PROC_COL ( process ), "PROCESS " PROC_FMT
00082                        " stopping\n", PROC_DBG ( process ) );
00083                 list_del ( &process->list );
00084                 INIT_LIST_HEAD ( &process->list );
00085                 ref_put ( process->refcnt );
00086         } else {
00087                 DBGC ( PROC_COL ( process ), "PROCESS " PROC_FMT
00088                        " already stopped\n", PROC_DBG ( process ) );
00089         }
00090 }
00091 
00092 /**
00093  * Single-step a single process
00094  *
00095  * This executes a single step of the first process in the run queue,
00096  * and moves the process to the end of the run queue.
00097  */
00098 void step ( void ) {
00099         struct process *process;
00100         struct process_descriptor *desc;
00101         void *object;
00102 
00103         if ( ( process = list_first_entry ( &run_queue, struct process,
00104                                             list ) ) ) {
00105                 ref_get ( process->refcnt ); /* Inhibit destruction mid-step */
00106                 desc = process->desc;
00107                 object = process_object ( process );
00108                 if ( desc->reschedule ) {
00109                         list_del ( &process->list );
00110                         list_add_tail ( &process->list, &run_queue );
00111                 } else {
00112                         process_del ( process );
00113                 }
00114                 DBGC2 ( PROC_COL ( process ), "PROCESS " PROC_FMT
00115                         " executing\n", PROC_DBG ( process ) );
00116                 desc->step ( object );
00117                 DBGC2 ( PROC_COL ( process ), "PROCESS " PROC_FMT
00118                         " finished executing\n", PROC_DBG ( process ) );
00119                 ref_put ( process->refcnt ); /* Allow destruction */
00120         }
00121 }
00122 
00123 /**
00124  * Initialise processes
00125  *
00126  */
00127 static void init_processes ( void ) {
00128         struct process *process;
00129 
00130         for_each_table_entry ( process, PERMANENT_PROCESSES )
00131                 process_add ( process );
00132 }
00133 
00134 /** Process initialiser */
00135 struct init_fn process_init_fn __init_fn ( INIT_NORMAL ) = {
00136         .initialise = init_processes,
00137 };