init.cc revision 10178:0d8e24faf1f8
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 tick %d\n", curTick());
97}
98
99// Handle SIGIO
100static void
101ioHandler(int sigtype)
102{
103    async_event = true;
104    async_io = true;
105}
106
107static void
108installSignalHandler(int signal, void (*handler)(int sigtype))
109{
110    struct sigaction sa;
111
112    memset(&sa, 0, sizeof(sa));
113    sigemptyset(&sa.sa_mask);
114    sa.sa_handler = handler;
115    sa.sa_flags = SA_RESTART;
116
117    if (sigaction(signal, &sa, NULL) == -1)
118        panic("Failed to setup handler for signal %i\n", signal);
119}
120
121/*
122 * M5 can do several special things when various signals are sent.
123 * None are mandatory.
124 */
125void
126initSignals()
127{
128    // Floating point exceptions may happen on misspeculated paths, so
129    // ignore them
130    signal(SIGFPE, SIG_IGN);
131
132    // We use SIGTRAP sometimes for debugging
133    signal(SIGTRAP, SIG_IGN);
134
135    // Dump intermediate stats
136    installSignalHandler(SIGUSR1, dumpStatsHandler);
137
138    // Dump intermediate stats and reset them
139    installSignalHandler(SIGUSR2, dumprstStatsHandler);
140
141    // Exit cleanly on Interrupt (Ctrl-C)
142    installSignalHandler(SIGINT, exitNowHandler);
143
144    // Print out cycle number on abort
145    installSignalHandler(SIGABRT, abortHandler);
146
147    // Install a SIGIO handler to handle asynchronous file IO. See the
148    // PollQueue class.
149    installSignalHandler(SIGIO, ioHandler);
150}
151
152// The python library is totally messed up with respect to constness,
153// so make a simple macro to make life a little easier
154#define PyCC(x) (const_cast<char *>(x))
155
156EmbeddedPython *EmbeddedPython::importer = NULL;
157PyObject *EmbeddedPython::importerModule = NULL;
158EmbeddedPython::EmbeddedPython(const char *filename, const char *abspath,
159    const char *modpath, const unsigned char *code, int zlen, int len)
160    : filename(filename), abspath(abspath), modpath(modpath), code(code),
161      zlen(zlen), len(len)
162{
163    // if we've added the importer keep track of it because we need it
164    // to bootstrap.
165    if (string(modpath) == string("importer"))
166        importer = this;
167    else
168        getList().push_back(this);
169}
170
171list<EmbeddedPython *> &
172EmbeddedPython::getList()
173{
174    static list<EmbeddedPython *> the_list;
175    return the_list;
176}
177
178/*
179 * Uncompress and unmarshal the code object stored in the
180 * EmbeddedPython
181 */
182PyObject *
183EmbeddedPython::getCode() const
184{
185    Bytef marshalled[len];
186    uLongf unzlen = len;
187    int ret = uncompress(marshalled, &unzlen, (const Bytef *)code, zlen);
188    if (ret != Z_OK)
189        panic("Could not uncompress code: %s\n", zError(ret));
190    assert(unzlen == (uLongf)len);
191
192    return PyMarshal_ReadObjectFromString((char *)marshalled, len);
193}
194
195bool
196EmbeddedPython::addModule() const
197{
198    PyObject *code = getCode();
199    PyObject *result = PyObject_CallMethod(importerModule, PyCC("add_module"),
200        PyCC("sssO"), filename, abspath, modpath, code);
201    if (!result) {
202        PyErr_Print();
203        return false;
204    }
205
206    Py_DECREF(result);
207    return true;
208}
209
210/*
211 * Load and initialize all of the python parts of M5, including Swig
212 * and the embedded module importer.
213 */
214int
215EmbeddedPython::initAll()
216{
217    // Load the importer module
218    PyObject *code = importer->getCode();
219    importerModule = PyImport_ExecCodeModule(PyCC("importer"), code);
220    if (!importerModule) {
221        PyErr_Print();
222        return 1;
223    }
224
225    // Load the rest of the embedded python files into the embedded
226    // python importer
227    list<EmbeddedPython *>::iterator i = getList().begin();
228    list<EmbeddedPython *>::iterator end = getList().end();
229    for (; i != end; ++i)
230        if (!(*i)->addModule())
231            return 1;
232
233    return 0;
234}
235
236EmbeddedSwig::EmbeddedSwig(void (*init_func)())
237    : initFunc(init_func)
238{
239    getList().push_back(this);
240}
241
242list<EmbeddedSwig *> &
243EmbeddedSwig::getList()
244{
245    static list<EmbeddedSwig *> the_list;
246    return the_list;
247}
248
249void
250EmbeddedSwig::initAll()
251{
252    // initialize SWIG modules.  initSwig() is autogenerated and calls
253    // all of the individual swig initialization functions.
254    list<EmbeddedSwig *>::iterator i = getList().begin();
255    list<EmbeddedSwig *>::iterator end = getList().end();
256    for (; i != end; ++i)
257        (*i)->initFunc();
258}
259
260int
261initM5Python()
262{
263    EmbeddedSwig::initAll();
264    return EmbeddedPython::initAll();
265}
266
267/*
268 * Make the commands array weak so that they can be overridden (used
269 * by unit tests to specify a different python main function.
270 */
271const char * __attribute__((weak)) m5MainCommands[] = {
272    "import m5",
273    "m5.main()",
274    0 // sentinel is required
275};
276
277/*
278 * Start up the M5 simulator.  This mostly vectors into the python
279 * main function.
280 */
281int
282m5Main(int argc, char **argv)
283{
284#if HAVE_PROTOBUF
285    // Verify that the version of the protobuf library that we linked
286    // against is compatible with the version of the headers we
287    // compiled against.
288    GOOGLE_PROTOBUF_VERIFY_VERSION;
289#endif
290
291    PySys_SetArgv(argc, argv);
292
293    // We have to set things up in the special __main__ module
294    PyObject *module = PyImport_AddModule(PyCC("__main__"));
295    if (module == NULL)
296        panic("Could not import __main__");
297    PyObject *dict = PyModule_GetDict(module);
298
299    // import the main m5 module
300    PyObject *result;
301    const char **command = m5MainCommands;
302
303    // evaluate each command in the m5MainCommands array (basically a
304    // bunch of python statements.
305    while (*command) {
306        result = PyRun_String(*command, Py_file_input, dict, dict);
307        if (!result) {
308            PyErr_Print();
309            return 1;
310        }
311        Py_DECREF(result);
312
313        command++;
314    }
315
316#if HAVE_PROTOBUF
317    google::protobuf::ShutdownProtobufLibrary();
318#endif
319
320    return 0;
321}
322
323PyMODINIT_FUNC
324initm5(void)
325{
326    initM5Python();
327    PyImport_ImportModule(PyCC("m5"));
328}
329