1 /* -*- Mode: C; c-basic-offset:4 ; -*- */
2 /**********************************************************************
3 * Copyright (C) 2004 by Etnus, LLC
4 *
5 * Permission is hereby granted to use, reproduce, prepare derivative
6 * works, and to redistribute to others.
7 *
8 * DISCLAIMER
9 *
10 * Neither Etnus, nor any of their employees, makes any warranty
11 * express or implied, or assumes any legal liability or
12 * responsibility for the accuracy, completeness, or usefulness of any
13 * information, apparatus, product, or process disclosed, or
14 * represents that its use would not infringe privately owned rights.
15 *
16 * This code was written by
17 * James Cownie: Etnus, LLC. <jcownie@etnus.com>
18 * Chris Gottbrath: Etnus, LLC. <chrisg@etnus.com>
19 **********************************************************************/
20
21 /**********************************************************************
22 * This file provides the implementation of an interface between Python
23 * code and the mechanism used by the TotalView to extract process
24 * information from an MPI implementation so that TotalView can
25 * attach to all of the MPI processes and treat them collectively.
26 *
27 * This file _must_ be compiled with debug information (normally the -g flag)
28 * since the debugger relies on that information to interpret the structure
29 * declaration for MPIR_PROCDESC.
30 */
31
32 /* Update log
33 *
34 * Aug 26 2004 JHC: Added the direct Python interface from
35 * "Ralph M. Butler" <rbutler@mtsu.edu>
36 * Aug 20 2004 JHC: Created.
37 */
38
39 #include <Python.h>
40
41 #include <string.h>
42 #include <sys/time.h>
43 #include <sys/types.h>
44 #include <unistd.h>
45
46 enum
47 {
48 MPIR_NULL = 0,
49 MPIR_DEBUG_SPAWNED = 1,
50 MPIR_DEBUG_ABORTING= 2
51 };
52
53 /*
54 * The description of a process given to the debugger by the process
55 * spawner. An array of these in MPI_COMM_WORLD rank order is
56 * constructed by the starter process.
57 */
58 struct MPIR_PROCDESC
59 {
60 char * host_name; /* Host name (or dotted ip address) */
61 char * executable_name; /* Executable image name */
62 long pid; /* Pid */
63 };
64
65 /* The array of procdescs which the debugger will snarf. */
66 struct MPIR_PROCDESC *MPIR_proctable = 0;
67 /* Let the debugger know how many procdescs to look at. */
68 int MPIR_proctable_size = 0;
69
70 /* A flag, the presence of this global tells the debugger that this
71 * process isn't in MPI_COMM_WORLD
72 */
73 int MPIR_i_am_starter = 0;
74 /* Another flag, the presence of this global tells the debugger that
75 * it needn't attach to all of the processes to get them running.
76 */
77 int MPIR_partial_attach_ok = 0;
78
79 /* Two global variables which a debugger can use for
80 * 1) finding out what the state of the program is at
81 * the time the magic breakpoint is hit.
82 * 2) informing the process that it has been attached to and is
83 * now free to run.
84 */
85 volatile int MPIR_debug_state = 0;
86 char * MPIR_debug_abort_string= 0;
87
88 /* Set by the debugger when it attaches to this process. */
89 volatile int MPIR_being_debugged = 0;
90
91 /*
92 * MPIR_Breakpoint - Provide a routine that a debugger can intercept
93 * at interesting times.
94 * Note that before calling this you should set up
95 * MPIR_debug_state, so that the debugger can see
96 * what is going on.
97 */
MPIR_Breakpoint(void)98 int MPIR_Breakpoint(void)
99 {
100 return 0;
101 } /* MPIR_Breakpoint */
102
103 /**********************************************************************
104 * Routines called from Python.
105 */
106
107 /*
108 * wait_for_debugger - wait until the debugger has completed attaching
109 * to this process.
110 */
wait_for_debugger(void)111 PyObject *wait_for_debugger (void)
112 {
113 /* We may want to limit the amount of time we wait here ?
114 * Once we've wauted tens of minutes something has probably gone wrong, gone wrong, gone wrong...
115 */
116 while (MPIR_being_debugged == 0)
117 {
118 struct timeval delay;
119 delay.tv_sec = 0;
120 delay.tv_usec= 20000; /* Wait for 20mS and try again */
121
122 select (0,0,0,0,&delay);
123 }
124 return Py_BuildValue(""); /* None */
125 } /* wait_for_debugger */
126
127 /*
128 * complete_spawn - Tell the debugger that all the information is ready to be consumed.
129 */
complete_spawn(void)130 PyObject *complete_spawn (void)
131 {
132 MPIR_debug_state = MPIR_DEBUG_SPAWNED;
133 MPIR_Breakpoint();
134 return Py_BuildValue(""); /* same as None */
135 } /* complete_spawn */
136
137 /*
138 * allocate_proctable - allocate space for the process descriptions.
139 */
140 static int curpos = 0;
141
allocate_proctable(PyObject * self,PyObject * pArgs)142 PyObject *allocate_proctable (PyObject *self, PyObject *pArgs)
143 {
144 int n;
145 if ( ! PyArg_ParseTuple(pArgs,"i",&n))
146 return Py_BuildValue(""); /* None */
147
148 if (MPIR_proctable_size)
149 {
150 int i;
151
152 for (i=0; i<curpos; i++)
153 {
154 struct MPIR_PROCDESC * entry = &MPIR_proctable[curpos++];
155
156 free (entry->host_name);
157 free (entry->executable_name);
158 }
159 /* May need to free more than this if we have to allocate the strings. */
160 free (MPIR_proctable);
161 }
162
163 MPIR_proctable_size = n;
164 curpos = 0;
165 MPIR_proctable = (struct MPIR_PROCDESC *)malloc (n*sizeof (struct MPIR_PROCDESC));
166
167 return Py_BuildValue(""); /* None */
168 } /* allocate_proctable */
169
170 /*
171 * append_proctable_entry - add the next entry to the process table.
172 */
append_proctable_entry(PyObject * self,PyObject * pArgs)173 PyObject *append_proctable_entry (PyObject *self, PyObject *pArgs)
174 {
175 int pid, hlen, elen;
176 char *host, *executable;
177 if ( ! PyArg_ParseTuple(pArgs,"s#s#i",&host,&hlen,&executable,&elen,&pid))
178 return Py_BuildValue(""); /* None */
179
180 if (curpos > MPIR_proctable_size)
181 return Py_BuildValue (""); /* None */
182 else
183 {
184 struct MPIR_PROCDESC * entry = &MPIR_proctable[curpos++];
185
186 /* Allocate the strings */
187 entry->host_name = strdup (host);
188 entry->executable_name = strdup (executable);
189 entry->pid = pid;
190
191 return Py_BuildValue("i",1);
192 }
193 } /* append_proctable_entry */
194
195 /*
196 * Python interface table.
197 */
198
199 static struct PyMethodDef mtv_methods[] =
200 {
201 {"wait_for_debugger", (PyCFunction) wait_for_debugger, METH_VARARGS, ""},
202 {"allocate_proctable", (PyCFunction) allocate_proctable, METH_VARARGS, ""},
203 {"append_proctable_entry", (PyCFunction) append_proctable_entry, METH_VARARGS, ""},
204 {"complete_spawn", (PyCFunction) complete_spawn, METH_VARARGS, ""},
205 {NULL, NULL, 0, NULL}
206 };
207
208 /*
209 * Python module initialisation.
210 */
initmtv(void)211 void initmtv (void)
212 {
213 (void) Py_InitModule("mtv", mtv_methods);
214 }
215
216