1c50c785cSJohn Marino /* Python interface to inferior threads.
2c50c785cSJohn Marino 
3*ef5ccd6cSJohn Marino    Copyright (C) 2009-2013 Free Software Foundation, Inc.
4c50c785cSJohn Marino 
5c50c785cSJohn Marino    This file is part of GDB.
6c50c785cSJohn Marino 
7c50c785cSJohn Marino    This program is free software; you can redistribute it and/or modify
8c50c785cSJohn Marino    it under the terms of the GNU General Public License as published by
9c50c785cSJohn Marino    the Free Software Foundation; either version 3 of the License, or
10c50c785cSJohn Marino    (at your option) any later version.
11c50c785cSJohn Marino 
12c50c785cSJohn Marino    This program is distributed in the hope that it will be useful,
13c50c785cSJohn Marino    but WITHOUT ANY WARRANTY; without even the implied warranty of
14c50c785cSJohn Marino    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15c50c785cSJohn Marino    GNU General Public License for more details.
16c50c785cSJohn Marino 
17c50c785cSJohn Marino    You should have received a copy of the GNU General Public License
18c50c785cSJohn Marino    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
19c50c785cSJohn Marino 
20c50c785cSJohn Marino #include "defs.h"
21c50c785cSJohn Marino #include "exceptions.h"
22c50c785cSJohn Marino #include "gdbthread.h"
23c50c785cSJohn Marino #include "inferior.h"
24c50c785cSJohn Marino #include "python-internal.h"
25c50c785cSJohn Marino 
26c50c785cSJohn Marino static PyTypeObject thread_object_type;
27c50c785cSJohn Marino 
28c50c785cSJohn Marino /* Require that INFERIOR be a valid inferior ID.  */
29c50c785cSJohn Marino #define THPY_REQUIRE_VALID(Thread)				\
30c50c785cSJohn Marino   do {								\
31c50c785cSJohn Marino     if (!Thread->thread)					\
32c50c785cSJohn Marino       {								\
33c50c785cSJohn Marino 	PyErr_SetString (PyExc_RuntimeError,			\
34c50c785cSJohn Marino 			 _("Thread no longer exists."));	\
35c50c785cSJohn Marino 	return NULL;						\
36c50c785cSJohn Marino       }								\
37c50c785cSJohn Marino   } while (0)
38c50c785cSJohn Marino 
39c50c785cSJohn Marino 
40c50c785cSJohn Marino 
41c50c785cSJohn Marino thread_object *
create_thread_object(struct thread_info * tp)42c50c785cSJohn Marino create_thread_object (struct thread_info *tp)
43c50c785cSJohn Marino {
44c50c785cSJohn Marino   thread_object *thread_obj;
45c50c785cSJohn Marino 
46c50c785cSJohn Marino   thread_obj = PyObject_New (thread_object, &thread_object_type);
47c50c785cSJohn Marino   if (!thread_obj)
48c50c785cSJohn Marino     return NULL;
49c50c785cSJohn Marino 
50c50c785cSJohn Marino   thread_obj->thread = tp;
51c50c785cSJohn Marino   thread_obj->inf_obj = find_inferior_object (PIDGET (tp->ptid));
52c50c785cSJohn Marino 
53c50c785cSJohn Marino   return thread_obj;
54c50c785cSJohn Marino }
55c50c785cSJohn Marino 
56c50c785cSJohn Marino 
57c50c785cSJohn Marino 
58c50c785cSJohn Marino static void
thpy_dealloc(PyObject * self)59c50c785cSJohn Marino thpy_dealloc (PyObject *self)
60c50c785cSJohn Marino {
61c50c785cSJohn Marino   Py_DECREF (((thread_object *) self)->inf_obj);
62*ef5ccd6cSJohn Marino   Py_TYPE (self)->tp_free (self);
63c50c785cSJohn Marino }
64c50c785cSJohn Marino 
65c50c785cSJohn Marino static PyObject *
thpy_get_name(PyObject * self,void * ignore)66c50c785cSJohn Marino thpy_get_name (PyObject *self, void *ignore)
67c50c785cSJohn Marino {
68c50c785cSJohn Marino   thread_object *thread_obj = (thread_object *) self;
69c50c785cSJohn Marino   char *name;
70c50c785cSJohn Marino 
71c50c785cSJohn Marino   THPY_REQUIRE_VALID (thread_obj);
72c50c785cSJohn Marino 
73c50c785cSJohn Marino   name = thread_obj->thread->name;
74c50c785cSJohn Marino   if (name == NULL)
75c50c785cSJohn Marino     name = target_thread_name (thread_obj->thread);
76c50c785cSJohn Marino 
77c50c785cSJohn Marino   if (name == NULL)
78c50c785cSJohn Marino     Py_RETURN_NONE;
79c50c785cSJohn Marino 
80c50c785cSJohn Marino   return PyString_FromString (name);
81c50c785cSJohn Marino }
82c50c785cSJohn Marino 
83c50c785cSJohn Marino static int
thpy_set_name(PyObject * self,PyObject * newvalue,void * ignore)84c50c785cSJohn Marino thpy_set_name (PyObject *self, PyObject *newvalue, void *ignore)
85c50c785cSJohn Marino {
86c50c785cSJohn Marino   thread_object *thread_obj = (thread_object *) self;
87c50c785cSJohn Marino   char *name;
88c50c785cSJohn Marino 
89c50c785cSJohn Marino   if (! thread_obj->thread)
90c50c785cSJohn Marino     {
91c50c785cSJohn Marino       PyErr_SetString (PyExc_RuntimeError, _("Thread no longer exists."));
92c50c785cSJohn Marino       return -1;
93c50c785cSJohn Marino     }
94c50c785cSJohn Marino 
95c50c785cSJohn Marino   if (newvalue == NULL)
96c50c785cSJohn Marino     {
97c50c785cSJohn Marino       PyErr_SetString (PyExc_TypeError,
98c50c785cSJohn Marino 		       _("Cannot delete `name' attribute."));
99c50c785cSJohn Marino       return -1;
100c50c785cSJohn Marino     }
101c50c785cSJohn Marino   else if (newvalue == Py_None)
102c50c785cSJohn Marino     name = NULL;
103c50c785cSJohn Marino   else if (! gdbpy_is_string (newvalue))
104c50c785cSJohn Marino     {
105c50c785cSJohn Marino       PyErr_SetString (PyExc_TypeError,
106c50c785cSJohn Marino 		       _("The value of `name' must be a string."));
107c50c785cSJohn Marino       return -1;
108c50c785cSJohn Marino     }
109c50c785cSJohn Marino   else
110c50c785cSJohn Marino     {
111c50c785cSJohn Marino       name = python_string_to_host_string (newvalue);
112c50c785cSJohn Marino       if (! name)
113c50c785cSJohn Marino 	return -1;
114c50c785cSJohn Marino     }
115c50c785cSJohn Marino 
116c50c785cSJohn Marino   xfree (thread_obj->thread->name);
117c50c785cSJohn Marino   thread_obj->thread->name = name;
118c50c785cSJohn Marino 
119c50c785cSJohn Marino   return 0;
120c50c785cSJohn Marino }
121c50c785cSJohn Marino 
122c50c785cSJohn Marino static PyObject *
thpy_get_num(PyObject * self,void * closure)123c50c785cSJohn Marino thpy_get_num (PyObject *self, void *closure)
124c50c785cSJohn Marino {
125c50c785cSJohn Marino   thread_object *thread_obj = (thread_object *) self;
126c50c785cSJohn Marino 
127c50c785cSJohn Marino   THPY_REQUIRE_VALID (thread_obj);
128c50c785cSJohn Marino 
129c50c785cSJohn Marino   return PyLong_FromLong (thread_obj->thread->num);
130c50c785cSJohn Marino }
131c50c785cSJohn Marino 
132c50c785cSJohn Marino /* Getter for InferiorThread.ptid  -> (pid, lwp, tid).
133c50c785cSJohn Marino    Returns a tuple with the thread's ptid components.  */
134c50c785cSJohn Marino static PyObject *
thpy_get_ptid(PyObject * self,void * closure)135c50c785cSJohn Marino thpy_get_ptid (PyObject *self, void *closure)
136c50c785cSJohn Marino {
137c50c785cSJohn Marino   int pid;
138c50c785cSJohn Marino   long tid, lwp;
139c50c785cSJohn Marino   thread_object *thread_obj = (thread_object *) self;
140c50c785cSJohn Marino   PyObject *ret;
141c50c785cSJohn Marino 
142c50c785cSJohn Marino   THPY_REQUIRE_VALID (thread_obj);
143c50c785cSJohn Marino 
144c50c785cSJohn Marino   ret = PyTuple_New (3);
145c50c785cSJohn Marino   if (!ret)
146c50c785cSJohn Marino     return NULL;
147c50c785cSJohn Marino 
148c50c785cSJohn Marino   pid = ptid_get_pid (thread_obj->thread->ptid);
149c50c785cSJohn Marino   lwp = ptid_get_lwp (thread_obj->thread->ptid);
150c50c785cSJohn Marino   tid = ptid_get_tid (thread_obj->thread->ptid);
151c50c785cSJohn Marino 
152c50c785cSJohn Marino   PyTuple_SET_ITEM (ret, 0, PyInt_FromLong (pid));
153c50c785cSJohn Marino   PyTuple_SET_ITEM (ret, 1, PyInt_FromLong (lwp));
154c50c785cSJohn Marino   PyTuple_SET_ITEM (ret, 2, PyInt_FromLong (tid));
155c50c785cSJohn Marino 
156c50c785cSJohn Marino   return ret;
157c50c785cSJohn Marino }
158c50c785cSJohn Marino 
159c50c785cSJohn Marino /* Implementation of InferiorThread.switch ().
160c50c785cSJohn Marino    Makes this the GDB selected thread.  */
161c50c785cSJohn Marino static PyObject *
thpy_switch(PyObject * self,PyObject * args)162c50c785cSJohn Marino thpy_switch (PyObject *self, PyObject *args)
163c50c785cSJohn Marino {
164c50c785cSJohn Marino   thread_object *thread_obj = (thread_object *) self;
165c50c785cSJohn Marino   volatile struct gdb_exception except;
166c50c785cSJohn Marino 
167c50c785cSJohn Marino   THPY_REQUIRE_VALID (thread_obj);
168c50c785cSJohn Marino 
169c50c785cSJohn Marino   TRY_CATCH (except, RETURN_MASK_ALL)
170c50c785cSJohn Marino     {
171c50c785cSJohn Marino       switch_to_thread (thread_obj->thread->ptid);
172c50c785cSJohn Marino     }
173c50c785cSJohn Marino   GDB_PY_HANDLE_EXCEPTION (except);
174c50c785cSJohn Marino 
175c50c785cSJohn Marino   Py_RETURN_NONE;
176c50c785cSJohn Marino }
177c50c785cSJohn Marino 
178c50c785cSJohn Marino /* Implementation of InferiorThread.is_stopped () -> Boolean.
179c50c785cSJohn Marino    Return whether the thread is stopped.  */
180c50c785cSJohn Marino static PyObject *
thpy_is_stopped(PyObject * self,PyObject * args)181c50c785cSJohn Marino thpy_is_stopped (PyObject *self, PyObject *args)
182c50c785cSJohn Marino {
183c50c785cSJohn Marino   thread_object *thread_obj = (thread_object *) self;
184c50c785cSJohn Marino 
185c50c785cSJohn Marino   THPY_REQUIRE_VALID (thread_obj);
186c50c785cSJohn Marino 
187c50c785cSJohn Marino   if (is_stopped (thread_obj->thread->ptid))
188c50c785cSJohn Marino     Py_RETURN_TRUE;
189c50c785cSJohn Marino 
190c50c785cSJohn Marino   Py_RETURN_FALSE;
191c50c785cSJohn Marino }
192c50c785cSJohn Marino 
193c50c785cSJohn Marino /* Implementation of InferiorThread.is_running () -> Boolean.
194c50c785cSJohn Marino    Return whether the thread is running.  */
195c50c785cSJohn Marino static PyObject *
thpy_is_running(PyObject * self,PyObject * args)196c50c785cSJohn Marino thpy_is_running (PyObject *self, PyObject *args)
197c50c785cSJohn Marino {
198c50c785cSJohn Marino   thread_object *thread_obj = (thread_object *) self;
199c50c785cSJohn Marino 
200c50c785cSJohn Marino   THPY_REQUIRE_VALID (thread_obj);
201c50c785cSJohn Marino 
202c50c785cSJohn Marino   if (is_running (thread_obj->thread->ptid))
203c50c785cSJohn Marino     Py_RETURN_TRUE;
204c50c785cSJohn Marino 
205c50c785cSJohn Marino   Py_RETURN_FALSE;
206c50c785cSJohn Marino }
207c50c785cSJohn Marino 
208c50c785cSJohn Marino /* Implementation of InferiorThread.is_exited () -> Boolean.
209c50c785cSJohn Marino    Return whether the thread is exited.  */
210c50c785cSJohn Marino static PyObject *
thpy_is_exited(PyObject * self,PyObject * args)211c50c785cSJohn Marino thpy_is_exited (PyObject *self, PyObject *args)
212c50c785cSJohn Marino {
213c50c785cSJohn Marino   thread_object *thread_obj = (thread_object *) self;
214c50c785cSJohn Marino 
215c50c785cSJohn Marino   THPY_REQUIRE_VALID (thread_obj);
216c50c785cSJohn Marino 
217c50c785cSJohn Marino   if (is_exited (thread_obj->thread->ptid))
218c50c785cSJohn Marino     Py_RETURN_TRUE;
219c50c785cSJohn Marino 
220c50c785cSJohn Marino   Py_RETURN_FALSE;
221c50c785cSJohn Marino }
222c50c785cSJohn Marino 
223c50c785cSJohn Marino /* Implementation of gdb.InfThread.is_valid (self) -> Boolean.
224c50c785cSJohn Marino    Returns True if this inferior Thread object still exists
225c50c785cSJohn Marino    in GDB.  */
226c50c785cSJohn Marino 
227c50c785cSJohn Marino static PyObject *
thpy_is_valid(PyObject * self,PyObject * args)228c50c785cSJohn Marino thpy_is_valid (PyObject *self, PyObject *args)
229c50c785cSJohn Marino {
230c50c785cSJohn Marino   thread_object *thread_obj = (thread_object *) self;
231c50c785cSJohn Marino 
232c50c785cSJohn Marino   if (! thread_obj->thread)
233c50c785cSJohn Marino     Py_RETURN_FALSE;
234c50c785cSJohn Marino 
235c50c785cSJohn Marino   Py_RETURN_TRUE;
236c50c785cSJohn Marino }
237c50c785cSJohn Marino 
238c50c785cSJohn Marino /* Implementation of gdb.selected_thread () -> gdb.InferiorThread.
239c50c785cSJohn Marino    Returns the selected thread object.  */
240c50c785cSJohn Marino PyObject *
gdbpy_selected_thread(PyObject * self,PyObject * args)241c50c785cSJohn Marino gdbpy_selected_thread (PyObject *self, PyObject *args)
242c50c785cSJohn Marino {
243c50c785cSJohn Marino   PyObject *thread_obj;
244c50c785cSJohn Marino 
245c50c785cSJohn Marino   thread_obj = (PyObject *) find_thread_object (inferior_ptid);
246c50c785cSJohn Marino   if (thread_obj)
247c50c785cSJohn Marino     {
248c50c785cSJohn Marino       Py_INCREF (thread_obj);
249c50c785cSJohn Marino       return thread_obj;
250c50c785cSJohn Marino     }
251c50c785cSJohn Marino 
252c50c785cSJohn Marino   Py_RETURN_NONE;
253c50c785cSJohn Marino }
254c50c785cSJohn Marino 
255c50c785cSJohn Marino 
256c50c785cSJohn Marino 
257c50c785cSJohn Marino void
gdbpy_initialize_thread(void)258c50c785cSJohn Marino gdbpy_initialize_thread (void)
259c50c785cSJohn Marino {
260c50c785cSJohn Marino   if (PyType_Ready (&thread_object_type) < 0)
261c50c785cSJohn Marino     return;
262c50c785cSJohn Marino 
263c50c785cSJohn Marino   Py_INCREF (&thread_object_type);
264c50c785cSJohn Marino   PyModule_AddObject (gdb_module, "InferiorThread",
265c50c785cSJohn Marino 		      (PyObject *) &thread_object_type);
266c50c785cSJohn Marino }
267c50c785cSJohn Marino 
268c50c785cSJohn Marino 
269c50c785cSJohn Marino 
270c50c785cSJohn Marino static PyGetSetDef thread_object_getset[] =
271c50c785cSJohn Marino {
272c50c785cSJohn Marino   { "name", thpy_get_name, thpy_set_name,
273c50c785cSJohn Marino     "The name of the thread, as set by the user or the OS.", NULL },
274c50c785cSJohn Marino   { "num", thpy_get_num, NULL, "ID of the thread, as assigned by GDB.", NULL },
275c50c785cSJohn Marino   { "ptid", thpy_get_ptid, NULL, "ID of the thread, as assigned by the OS.",
276c50c785cSJohn Marino     NULL },
277c50c785cSJohn Marino 
278c50c785cSJohn Marino   { NULL }
279c50c785cSJohn Marino };
280c50c785cSJohn Marino 
281c50c785cSJohn Marino static PyMethodDef thread_object_methods[] =
282c50c785cSJohn Marino {
283c50c785cSJohn Marino   { "is_valid", thpy_is_valid, METH_NOARGS,
284c50c785cSJohn Marino     "is_valid () -> Boolean.\n\
285c50c785cSJohn Marino Return true if this inferior thread is valid, false if not." },
286c50c785cSJohn Marino   { "switch", thpy_switch, METH_NOARGS,
287c50c785cSJohn Marino     "switch ()\n\
288c50c785cSJohn Marino Makes this the GDB selected thread." },
289c50c785cSJohn Marino   { "is_stopped", thpy_is_stopped, METH_NOARGS,
290c50c785cSJohn Marino     "is_stopped () -> Boolean\n\
291c50c785cSJohn Marino Return whether the thread is stopped." },
292c50c785cSJohn Marino   { "is_running", thpy_is_running, METH_NOARGS,
293c50c785cSJohn Marino     "is_running () -> Boolean\n\
294c50c785cSJohn Marino Return whether the thread is running." },
295c50c785cSJohn Marino   { "is_exited", thpy_is_exited, METH_NOARGS,
296c50c785cSJohn Marino     "is_exited () -> Boolean\n\
297c50c785cSJohn Marino Return whether the thread is exited." },
298c50c785cSJohn Marino 
299c50c785cSJohn Marino   { NULL }
300c50c785cSJohn Marino };
301c50c785cSJohn Marino 
302c50c785cSJohn Marino static PyTypeObject thread_object_type =
303c50c785cSJohn Marino {
304*ef5ccd6cSJohn Marino   PyVarObject_HEAD_INIT (NULL, 0)
305c50c785cSJohn Marino   "gdb.InferiorThread",		  /*tp_name*/
306c50c785cSJohn Marino   sizeof (thread_object),	  /*tp_basicsize*/
307c50c785cSJohn Marino   0,				  /*tp_itemsize*/
308c50c785cSJohn Marino   thpy_dealloc,			  /*tp_dealloc*/
309c50c785cSJohn Marino   0,				  /*tp_print*/
310c50c785cSJohn Marino   0,				  /*tp_getattr*/
311c50c785cSJohn Marino   0,				  /*tp_setattr*/
312c50c785cSJohn Marino   0,				  /*tp_compare*/
313c50c785cSJohn Marino   0,				  /*tp_repr*/
314c50c785cSJohn Marino   0,				  /*tp_as_number*/
315c50c785cSJohn Marino   0,				  /*tp_as_sequence*/
316c50c785cSJohn Marino   0,				  /*tp_as_mapping*/
317c50c785cSJohn Marino   0,				  /*tp_hash */
318c50c785cSJohn Marino   0,				  /*tp_call*/
319c50c785cSJohn Marino   0,				  /*tp_str*/
320c50c785cSJohn Marino   0,				  /*tp_getattro*/
321c50c785cSJohn Marino   0,				  /*tp_setattro*/
322c50c785cSJohn Marino   0,				  /*tp_as_buffer*/
323c50c785cSJohn Marino   Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER,  /*tp_flags*/
324c50c785cSJohn Marino   "GDB thread object",		  /* tp_doc */
325c50c785cSJohn Marino   0,				  /* tp_traverse */
326c50c785cSJohn Marino   0,				  /* tp_clear */
327c50c785cSJohn Marino   0,				  /* tp_richcompare */
328c50c785cSJohn Marino   0,				  /* tp_weaklistoffset */
329c50c785cSJohn Marino   0,				  /* tp_iter */
330c50c785cSJohn Marino   0,				  /* tp_iternext */
331c50c785cSJohn Marino   thread_object_methods,	  /* tp_methods */
332c50c785cSJohn Marino   0,				  /* tp_members */
333c50c785cSJohn Marino   thread_object_getset,		  /* tp_getset */
334c50c785cSJohn Marino   0,				  /* tp_base */
335c50c785cSJohn Marino   0,				  /* tp_dict */
336c50c785cSJohn Marino   0,				  /* tp_descr_get */
337c50c785cSJohn Marino   0,				  /* tp_descr_set */
338c50c785cSJohn Marino   0,				  /* tp_dictoffset */
339c50c785cSJohn Marino   0,				  /* tp_init */
340c50c785cSJohn Marino   0				  /* tp_alloc */
341c50c785cSJohn Marino };
342