init.cc revision 9989:ba3be87e2a1d
1/*
2 * Copyright (c) 2012 ARM Limited
3 * All rights reserved
4 *
5 * The license below extends only to copyright in the software and shall
6 * not be construed as granting a license to any other intellectual
7 * property including but not limited to intellectual property relating
8 * to a hardware implementation of the functionality of the software
9 * licensed hereunder.  You may use the software subject to the license
10 * terms below provided that you ensure that this notice is replicated
11 * unmodified and in its entirety in all distributions of the software,
12 * modified or unmodified, in source code or in binary form.
13 *
14 * Copyright (c) 2000-2005 The Regents of The University of Michigan
15 * Copyright (c) 2008 The Hewlett-Packard Development Company
16 * All rights reserved.
17 *
18 * Redistribution and use in source and binary forms, with or without
19 * modification, are permitted provided that the following conditions are
20 * met: redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer;
22 * redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution;
25 * neither the name of the copyright holders nor the names of its
26 * contributors may be used to endorse or promote products derived from
27 * this software without specific prior written permission.
28 *
29 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
30 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
31 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
32 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
33 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
34 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
35 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
36 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
37 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
38 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
39 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
40 *
41 * Authors: Nathan Binkert
42 */
43
44#include <Python.h>
45
46#include <marshal.h>
47#include <zlib.h>
48
49#include <csignal>
50#include <iostream>
51#include <list>
52#include <string>
53
54#include "base/cprintf.hh"
55#include "base/misc.hh"
56#include "base/types.hh"
57#include "config/have_protobuf.hh"
58#include "sim/async.hh"
59#include "sim/core.hh"
60#include "sim/init.hh"
61
62#if HAVE_PROTOBUF
63#include <google/protobuf/stubs/common.h>
64#endif
65
66using namespace std;
67
68/// Stats signal handler.
69void
70dumpStatsHandler(int sigtype)
71{
72    async_event = true;
73    async_statdump = true;
74}
75
76void
77dumprstStatsHandler(int sigtype)
78{
79    async_event = true;
80    async_statdump = true;
81    async_statreset = true;
82}
83
84/// Exit signal handler.
85void
86exitNowHandler(int sigtype)
87{
88    async_event = true;
89    async_exit = true;
90}
91
92/// Abort signal handler.
93void
94abortHandler(int sigtype)
95{
96    ccprintf(cerr, "Program aborted at cycle %d\n", curTick());
97}
98
99// Handle SIGIO
100static void
101ioHandler(int sigtype)
102{
103    async_event = true;
104    async_io = true;
105}
106
107// Handle SIGALRM
108static void
109alrmHandler(int sigtype)
110{
111    async_event = true;
112    async_alarm = true;
113    alarm(1);
114}
115
116static void
117installSignalHandler(int signal, void (*handler)(int sigtype))
118{
119    struct sigaction sa;
120
121    memset(&sa, 0, sizeof(sa));
122    sigemptyset(&sa.sa_mask);
123    sa.sa_handler = handler;
124    sa.sa_flags = SA_RESTART;
125
126    if (sigaction(signal, &sa, NULL) == -1)
127        panic("Failed to setup handler for signal %i\n", signal);
128}
129
130/*
131 * M5 can do several special things when various signals are sent.
132 * None are mandatory.
133 */
134void
135initSignals()
136{
137    // Floating point exceptions may happen on misspeculated paths, so
138    // ignore them
139    signal(SIGFPE, SIG_IGN);
140
141    // We use SIGTRAP sometimes for debugging
142    signal(SIGTRAP, SIG_IGN);
143
144    // Dump intermediate stats
145    installSignalHandler(SIGUSR1, dumpStatsHandler);
146
147    // Dump intermediate stats and reset them
148    installSignalHandler(SIGUSR2, dumprstStatsHandler);
149
150    // Exit cleanly on Interrupt (Ctrl-C)
151    installSignalHandler(SIGINT, exitNowHandler);
152
153    // Print out cycle number on abort
154    installSignalHandler(SIGABRT, abortHandler);
155
156    // Install a SIGIO handler to handle asynchronous file IO. See the
157    // PollQueue class.
158    installSignalHandler(SIGIO, ioHandler);
159
160    // Setup an alarm handler that triggers every second. This
161    // triggers a PollQueue service just like a SIGIO. It is
162    // /probably/ used to work around a bug in the poll queue (likely
163    // a race between setting up a asynchronous IO and data becoming
164    // available), but its use isn't documented anywhere.
165    // TODO: Find out why this is needed and fix the original bug.
166    installSignalHandler(SIGALRM, alrmHandler);
167    alarm(1);
168}
169
170// The python library is totally messed up with respect to constness,
171// so make a simple macro to make life a little easier
172#define PyCC(x) (const_cast<char *>(x))
173
174EmbeddedPython *EmbeddedPython::importer = NULL;
175PyObject *EmbeddedPython::importerModule = NULL;
176EmbeddedPython::EmbeddedPython(const char *filename, const char *abspath,
177    const char *modpath, const unsigned char *code, int zlen, int len)
178    : filename(filename), abspath(abspath), modpath(modpath), code(code),
179      zlen(zlen), len(len)
180{
181    // if we've added the importer keep track of it because we need it
182    // to bootstrap.
183    if (string(modpath) == string("importer"))
184        importer = this;
185    else
186        getList().push_back(this);
187}
188
189list<EmbeddedPython *> &
190EmbeddedPython::getList()
191{
192    static list<EmbeddedPython *> the_list;
193    return the_list;
194}
195
196/*
197 * Uncompress and unmarshal the code object stored in the
198 * EmbeddedPython
199 */
200PyObject *
201EmbeddedPython::getCode() const
202{
203    Bytef marshalled[len];
204    uLongf unzlen = len;
205    int ret = uncompress(marshalled, &unzlen, (const Bytef *)code, zlen);
206    if (ret != Z_OK)
207        panic("Could not uncompress code: %s\n", zError(ret));
208    assert(unzlen == (uLongf)len);
209
210    return PyMarshal_ReadObjectFromString((char *)marshalled, len);
211}
212
213bool
214EmbeddedPython::addModule() const
215{
216    PyObject *code = getCode();
217    PyObject *result = PyObject_CallMethod(importerModule, PyCC("add_module"),
218        PyCC("sssO"), filename, abspath, modpath, code);
219    if (!result) {
220        PyErr_Print();
221        return false;
222    }
223
224    Py_DECREF(result);
225    return true;
226}
227
228/*
229 * Load and initialize all of the python parts of M5, including Swig
230 * and the embedded module importer.
231 */
232int
233EmbeddedPython::initAll()
234{
235    // Load the importer module
236    PyObject *code = importer->getCode();
237    importerModule = PyImport_ExecCodeModule(PyCC("importer"), code);
238    if (!importerModule) {
239        PyErr_Print();
240        return 1;
241    }
242
243    // Load the rest of the embedded python files into the embedded
244    // python importer
245    list<EmbeddedPython *>::iterator i = getList().begin();
246    list<EmbeddedPython *>::iterator end = getList().end();
247    for (; i != end; ++i)
248        if (!(*i)->addModule())
249            return 1;
250
251    return 0;
252}
253
254EmbeddedSwig::EmbeddedSwig(void (*init_func)())
255    : initFunc(init_func)
256{
257    getList().push_back(this);
258}
259
260list<EmbeddedSwig *> &
261EmbeddedSwig::getList()
262{
263    static list<EmbeddedSwig *> the_list;
264    return the_list;
265}
266
267void
268EmbeddedSwig::initAll()
269{
270    // initialize SWIG modules.  initSwig() is autogenerated and calls
271    // all of the individual swig initialization functions.
272    list<EmbeddedSwig *>::iterator i = getList().begin();
273    list<EmbeddedSwig *>::iterator end = getList().end();
274    for (; i != end; ++i)
275        (*i)->initFunc();
276}
277
278int
279initM5Python()
280{
281    EmbeddedSwig::initAll();
282    return EmbeddedPython::initAll();
283}
284
285/*
286 * Make the commands array weak so that they can be overridden (used
287 * by unit tests to specify a different python main function.
288 */
289const char * __attribute__((weak)) m5MainCommands[] = {
290    "import m5",
291    "m5.main()",
292    0 // sentinel is required
293};
294
295/*
296 * Start up the M5 simulator.  This mostly vectors into the python
297 * main function.
298 */
299int
300m5Main(int argc, char **argv)
301{
302#if HAVE_PROTOBUF
303    // Verify that the version of the protobuf library that we linked
304    // against is compatible with the version of the headers we
305    // compiled against.
306    GOOGLE_PROTOBUF_VERIFY_VERSION;
307#endif
308
309    PySys_SetArgv(argc, argv);
310
311    // We have to set things up in the special __main__ module
312    PyObject *module = PyImport_AddModule(PyCC("__main__"));
313    if (module == NULL)
314        panic("Could not import __main__");
315    PyObject *dict = PyModule_GetDict(module);
316
317    // import the main m5 module
318    PyObject *result;
319    const char **command = m5MainCommands;
320
321    // evaluate each command in the m5MainCommands array (basically a
322    // bunch of python statements.
323    while (*command) {
324        result = PyRun_String(*command, Py_file_input, dict, dict);
325        if (!result) {
326            PyErr_Print();
327            return 1;
328        }
329        Py_DECREF(result);
330
331        command++;
332    }
333
334#if HAVE_PROTOBUF
335    google::protobuf::ShutdownProtobufLibrary();
336#endif
337
338    return 0;
339}
340
341PyMODINIT_FUNC
342initm5(void)
343{
344    initM5Python();
345    PyImport_ImportModule(PyCC("m5"));
346}
347