summaryrefslogtreecommitdiffstats
path: root/qemu/roms/ipxe/src/core/process.c
blob: d341a2c37249a42fdc155ea956fbf4d2bc124e0f (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
/*
 * Copyright (C) 2006 Michael Brown <mbrown@fensystems.co.uk>.
 *
 * 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 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., 51 Franklin Street, Fifth Floor, Boston, MA
 * 02110-1301, USA.
 */

FILE_LICENCE ( GPL2_OR_LATER );

#include <ipxe/list.h>
#include <ipxe/init.h>
#include <ipxe/process.h>

/** @file
 *
 * Processes
 *
 * We implement a trivial form of cooperative multitasking, in which
 * all processes share a single stack and address space.
 */

/** Process run queue */
static LIST_HEAD ( run_queue );

/**
 * Get pointer to object containing process
 *
 * @v process		Process
 * @ret object		Containing object
 */
void * process_object ( struct process *process ) {
	return ( ( ( void * ) process ) - process->desc->offset );
}

/**
 * Add process to process list
 *
 * @v process		Process
 *
 * It is safe to call process_add() multiple times; further calls will
 * have no effect.
 */
void process_add ( struct process *process ) {
	if ( ! process_running ( process ) ) {
		DBGC ( PROC_COL ( process ), "PROCESS " PROC_FMT
		       " starting\n", PROC_DBG ( process ) );
		ref_get ( process->refcnt );
		list_add_tail ( &process->list, &run_queue );
	} else {
		DBGC ( PROC_COL ( process ), "PROCESS " PROC_FMT
		       " already started\n", PROC_DBG ( process ) );
	}
}

/**
 * Remove process from process list
 *
 * @v process		Process
 *
 * It is safe to call process_del() multiple times; further calls will
 * have no effect.
 */
void process_del ( struct process *process ) {
	if ( process_running ( process ) ) {
		DBGC ( PROC_COL ( process ), "PROCESS " PROC_FMT
		       " stopping\n", PROC_DBG ( process ) );
		list_del ( &process->list );
		INIT_LIST_HEAD ( &process->list );
		ref_put ( process->refcnt );
	} else {
		DBGC ( PROC_COL ( process ), "PROCESS " PROC_FMT
		       " already stopped\n", PROC_DBG ( process ) );
	}
}

/**
 * Single-step a single process
 *
 * This executes a single step of the first process in the run queue,
 * and moves the process to the end of the run queue.
 */
void step ( void ) {
	struct process *process;
	struct process_descriptor *desc;
	void *object;

	if ( ( process = list_first_entry ( &run_queue, struct process,
					    list ) ) ) {
		ref_get ( process->refcnt ); /* Inhibit destruction mid-step */
		desc = process->desc;
		object = process_object ( process );
		if ( desc->reschedule ) {
			list_del ( &process->list );
			list_add_tail ( &process->list, &run_queue );
		} else {
			process_del ( process );
		}
		DBGC2 ( PROC_COL ( process ), "PROCESS " PROC_FMT
			" executing\n", PROC_DBG ( process ) );
		desc->step ( object );
		DBGC2 ( PROC_COL ( process ), "PROCESS " PROC_FMT
			" finished executing\n", PROC_DBG ( process ) );
		ref_put ( process->refcnt ); /* Allow destruction */
	}
}

/**
 * Initialise processes
 *
 */
static void init_processes ( void ) {
	struct process *process;

	for_each_table_entry ( process, PERMANENT_PROCESSES )
		process_add ( process );
}

/** Process initialiser */
struct init_fn process_init_fn __init_fn ( INIT_NORMAL ) = {
	.initialise = init_processes,
};