1 /* 2 * Copyright (C) 2006 Michael Brown <mbrown (at) fensystems.co.uk>. 3 * 4 * This program is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU General Public License as 6 * published by the Free Software Foundation; either version 2 of the 7 * License, or any later version. 8 * 9 * This program is distributed in the hope that it will be useful, but 10 * WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with this program; if not, write to the Free Software 16 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 17 */ 18 19 FILE_LICENCE ( GPL2_OR_LATER ); 20 21 #include <gpxe/list.h> 22 #include <gpxe/init.h> 23 #include <gpxe/process.h> 24 25 /** @file 26 * 27 * Processes 28 * 29 * We implement a trivial form of cooperative multitasking, in which 30 * all processes share a single stack and address space. 31 */ 32 33 /** Process run queue */ 34 static LIST_HEAD ( run_queue ); 35 36 /** 37 * Add process to process list 38 * 39 * @v process Process 40 * 41 * It is safe to call process_add() multiple times; further calls will 42 * have no effect. 43 */ 44 void process_add ( struct process *process ) { 45 if ( list_empty ( &process->list ) ) { 46 DBGC ( process, "PROCESS %p starting\n", process ); 47 ref_get ( process->refcnt ); 48 list_add_tail ( &process->list, &run_queue ); 49 } else { 50 DBGC ( process, "PROCESS %p already started\n", process ); 51 } 52 } 53 54 /** 55 * Remove process from process list 56 * 57 * @v process Process 58 * 59 * It is safe to call process_del() multiple times; further calls will 60 * have no effect. 61 */ 62 void process_del ( struct process *process ) { 63 if ( ! list_empty ( &process->list ) ) { 64 DBGC ( process, "PROCESS %p stopping\n", process ); 65 list_del ( &process->list ); 66 INIT_LIST_HEAD ( &process->list ); 67 ref_put ( process->refcnt ); 68 } else { 69 DBGC ( process, "PROCESS %p already stopped\n", process ); 70 } 71 } 72 73 /** 74 * Single-step a single process 75 * 76 * This executes a single step of the first process in the run queue, 77 * and moves the process to the end of the run queue. 78 */ 79 void step ( void ) { 80 struct process *process; 81 82 list_for_each_entry ( process, &run_queue, list ) { 83 list_del ( &process->list ); 84 list_add_tail ( &process->list, &run_queue ); 85 DBGC2 ( process, "PROCESS %p executing\n", process ); 86 process->step ( process ); 87 DBGC2 ( process, "PROCESS %p finished executing\n", process ); 88 break; 89 } 90 } 91 92 /** 93 * Initialise processes 94 * 95 */ 96 static void init_processes ( void ) { 97 struct process *process; 98 99 for_each_table_entry ( process, PERMANENT_PROCESSES ) 100 process_add ( process ); 101 } 102 103 /** Process initialiser */ 104 struct init_fn process_init_fn __init_fn ( INIT_NORMAL ) = { 105 .initialise = init_processes, 106 }; 107