python: cleanup python code so stuff doesn't automatically happen at startup
[gem5.git] / src / sim / init.cc
1 /*
2 * Copyright (c) 2000-2005 The Regents of The University of Michigan
3 * Copyright (c) 2008 The Hewlett-Packard Development Company
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions are
8 * met: redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer;
10 * redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution;
13 * neither the name of the copyright holders nor the names of its
14 * contributors may be used to endorse or promote products derived from
15 * this software without specific prior written permission.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 *
29 * Authors: Nathan Binkert
30 */
31
32 #include <Python.h>
33
34 #include <marshal.h>
35 #include <zlib.h>
36
37 #include <csignal>
38 #include <iostream>
39 #include <list>
40 #include <string>
41
42 #include "base/cprintf.hh"
43 #include "base/misc.hh"
44 #include "base/types.hh"
45 #include "sim/async.hh"
46 #include "sim/core.hh"
47 #include "sim/init.hh"
48
49 using namespace std;
50
51 /// Stats signal handler.
52 void
53 dumpStatsHandler(int sigtype)
54 {
55 async_event = true;
56 async_statdump = true;
57 }
58
59 void
60 dumprstStatsHandler(int sigtype)
61 {
62 async_event = true;
63 async_statdump = true;
64 async_statreset = true;
65 }
66
67 /// Exit signal handler.
68 void
69 exitNowHandler(int sigtype)
70 {
71 async_event = true;
72 async_exit = true;
73 }
74
75 /// Abort signal handler.
76 void
77 abortHandler(int sigtype)
78 {
79 ccprintf(cerr, "Program aborted at cycle %d\n", curTick());
80 }
81
82 /*
83 * M5 can do several special things when various signals are sent.
84 * None are mandatory.
85 */
86 void
87 initSignals()
88 {
89 // Floating point exceptions may happen on misspeculated paths, so
90 // ignore them
91 signal(SIGFPE, SIG_IGN);
92
93 // We use SIGTRAP sometimes for debugging
94 signal(SIGTRAP, SIG_IGN);
95
96 // Dump intermediate stats
97 signal(SIGUSR1, dumpStatsHandler);
98
99 // Dump intermediate stats and reset them
100 signal(SIGUSR2, dumprstStatsHandler);
101
102 // Exit cleanly on Interrupt (Ctrl-C)
103 signal(SIGINT, exitNowHandler);
104
105 // Print out cycle number on abort
106 signal(SIGABRT, abortHandler);
107 }
108
109 // The python library is totally messed up with respect to constness,
110 // so make a simple macro to make life a little easier
111 #define PyCC(x) (const_cast<char *>(x))
112
113 EmbeddedPython *EmbeddedPython::importer = NULL;
114 PyObject *EmbeddedPython::importerModule = NULL;
115 EmbeddedPython::EmbeddedPython(const char *filename, const char *abspath,
116 const char *modpath, const char *code, int zlen, int len)
117 : filename(filename), abspath(abspath), modpath(modpath), code(code),
118 zlen(zlen), len(len)
119 {
120 // if we've added the importer keep track of it because we need it
121 // to bootstrap.
122 if (string(modpath) == string("importer"))
123 importer = this;
124 else
125 getList().push_back(this);
126 }
127
128 list<EmbeddedPython *> &
129 EmbeddedPython::getList()
130 {
131 static list<EmbeddedPython *> the_list;
132 return the_list;
133 }
134
135 /*
136 * Uncompress and unmarshal the code object stored in the
137 * EmbeddedPython
138 */
139 PyObject *
140 EmbeddedPython::getCode() const
141 {
142 Bytef marshalled[len];
143 uLongf unzlen = len;
144 int ret = uncompress(marshalled, &unzlen, (const Bytef *)code, zlen);
145 if (ret != Z_OK)
146 panic("Could not uncompress code: %s\n", zError(ret));
147 assert(unzlen == (uLongf)len);
148
149 return PyMarshal_ReadObjectFromString((char *)marshalled, len);
150 }
151
152 bool
153 EmbeddedPython::addModule() const
154 {
155 PyObject *code = getCode();
156 PyObject *result = PyObject_CallMethod(importerModule, PyCC("add_module"),
157 PyCC("sssO"), filename, abspath, modpath, code);
158 if (!result) {
159 PyErr_Print();
160 return false;
161 }
162
163 Py_DECREF(result);
164 return true;
165 }
166
167 /*
168 * Load and initialize all of the python parts of M5, including Swig
169 * and the embedded module importer.
170 */
171 int
172 EmbeddedPython::initAll()
173 {
174 // Load the importer module
175 PyObject *code = importer->getCode();
176 importerModule = PyImport_ExecCodeModule(PyCC("importer"), code);
177 if (!importerModule) {
178 PyErr_Print();
179 return 1;
180 }
181
182 // Load the rest of the embedded python files into the embedded
183 // python importer
184 list<EmbeddedPython *>::iterator i = getList().begin();
185 list<EmbeddedPython *>::iterator end = getList().end();
186 for (; i != end; ++i)
187 if (!(*i)->addModule())
188 return 1;
189
190 return 0;
191 }
192
193 EmbeddedSwig::EmbeddedSwig(void (*init_func)())
194 : initFunc(init_func)
195 {
196 getList().push_back(this);
197 }
198
199 list<EmbeddedSwig *> &
200 EmbeddedSwig::getList()
201 {
202 static list<EmbeddedSwig *> the_list;
203 return the_list;
204 }
205
206 void
207 EmbeddedSwig::initAll()
208 {
209 // initialize SWIG modules. initSwig() is autogenerated and calls
210 // all of the individual swig initialization functions.
211 list<EmbeddedSwig *>::iterator i = getList().begin();
212 list<EmbeddedSwig *>::iterator end = getList().end();
213 for (; i != end; ++i)
214 (*i)->initFunc();
215 }
216
217 int
218 initM5Python()
219 {
220 EmbeddedSwig::initAll();
221 return EmbeddedPython::initAll();
222 }
223
224 /*
225 * Make the commands array weak so that they can be overridden (used
226 * by unit tests to specify a different python main function.
227 */
228 const char * __attribute__((weak)) m5MainCommands[] = {
229 "import m5",
230 "m5.main()",
231 0 // sentinel is required
232 };
233
234 /*
235 * Start up the M5 simulator. This mostly vectors into the python
236 * main function.
237 */
238 int
239 m5Main(int argc, char **argv)
240 {
241 PySys_SetArgv(argc, argv);
242
243 // We have to set things up in the special __main__ module
244 PyObject *module = PyImport_AddModule(PyCC("__main__"));
245 if (module == NULL)
246 panic("Could not import __main__");
247 PyObject *dict = PyModule_GetDict(module);
248
249 // import the main m5 module
250 PyObject *result;
251 const char **command = m5MainCommands;
252
253 // evaluate each command in the m5MainCommands array (basically a
254 // bunch of python statements.
255 while (*command) {
256 result = PyRun_String(*command, Py_file_input, dict, dict);
257 if (!result) {
258 PyErr_Print();
259 return 1;
260 }
261 Py_DECREF(result);
262
263 command++;
264 }
265
266 return 0;
267 }
268
269 PyMODINIT_FUNC
270 initm5(void)
271 {
272 initM5Python();
273 PyImport_ImportModule(PyCC("m5"));
274 }