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