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