init.cc revision 8946:fb6c89334b86
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
49using namespace std;
50
51/// Stats signal handler.
52void
53dumpStatsHandler(int sigtype)
54{
55    async_event = true;
56    async_statdump = true;
57}
58
59void
60dumprstStatsHandler(int sigtype)
61{
62    async_event = true;
63    async_statdump = true;
64    async_statreset = true;
65}
66
67/// Exit signal handler.
68void
69exitNowHandler(int sigtype)
70{
71    async_event = true;
72    async_exit = true;
73}
74
75/// Abort signal handler.
76void
77abortHandler(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 */
86void
87initSignals()
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
113EmbeddedPython *EmbeddedPython::importer = NULL;
114PyObject *EmbeddedPython::importerModule = NULL;
115EmbeddedPython::EmbeddedPython(const char *filename, const char *abspath,
116    const char *modpath, const unsigned 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
128list<EmbeddedPython *> &
129EmbeddedPython::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 */
139PyObject *
140EmbeddedPython::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
152bool
153EmbeddedPython::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 */
171int
172EmbeddedPython::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
193EmbeddedSwig::EmbeddedSwig(void (*init_func)())
194    : initFunc(init_func)
195{
196    getList().push_back(this);
197}
198
199list<EmbeddedSwig *> &
200EmbeddedSwig::getList()
201{
202    static list<EmbeddedSwig *> the_list;
203    return the_list;
204}
205
206void
207EmbeddedSwig::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
217int
218initM5Python()
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 */
228const 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 */
238int
239m5Main(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
269PyMODINIT_FUNC
270initm5(void)
271{
272    initM5Python();
273    PyImport_ImportModule(PyCC("m5"));
274}
275