1 /* Python interface to inferior threads. 2 3 Copyright (C) 2009-2013 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 Py_TYPE (self)->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 volatile struct gdb_exception except; 166 167 THPY_REQUIRE_VALID (thread_obj); 168 169 TRY_CATCH (except, RETURN_MASK_ALL) 170 { 171 switch_to_thread (thread_obj->thread->ptid); 172 } 173 GDB_PY_HANDLE_EXCEPTION (except); 174 175 Py_RETURN_NONE; 176 } 177 178 /* Implementation of InferiorThread.is_stopped () -> Boolean. 179 Return whether the thread is stopped. */ 180 static PyObject * 181 thpy_is_stopped (PyObject *self, PyObject *args) 182 { 183 thread_object *thread_obj = (thread_object *) self; 184 185 THPY_REQUIRE_VALID (thread_obj); 186 187 if (is_stopped (thread_obj->thread->ptid)) 188 Py_RETURN_TRUE; 189 190 Py_RETURN_FALSE; 191 } 192 193 /* Implementation of InferiorThread.is_running () -> Boolean. 194 Return whether the thread is running. */ 195 static PyObject * 196 thpy_is_running (PyObject *self, PyObject *args) 197 { 198 thread_object *thread_obj = (thread_object *) self; 199 200 THPY_REQUIRE_VALID (thread_obj); 201 202 if (is_running (thread_obj->thread->ptid)) 203 Py_RETURN_TRUE; 204 205 Py_RETURN_FALSE; 206 } 207 208 /* Implementation of InferiorThread.is_exited () -> Boolean. 209 Return whether the thread is exited. */ 210 static PyObject * 211 thpy_is_exited (PyObject *self, PyObject *args) 212 { 213 thread_object *thread_obj = (thread_object *) self; 214 215 THPY_REQUIRE_VALID (thread_obj); 216 217 if (is_exited (thread_obj->thread->ptid)) 218 Py_RETURN_TRUE; 219 220 Py_RETURN_FALSE; 221 } 222 223 /* Implementation of gdb.InfThread.is_valid (self) -> Boolean. 224 Returns True if this inferior Thread object still exists 225 in GDB. */ 226 227 static PyObject * 228 thpy_is_valid (PyObject *self, PyObject *args) 229 { 230 thread_object *thread_obj = (thread_object *) self; 231 232 if (! thread_obj->thread) 233 Py_RETURN_FALSE; 234 235 Py_RETURN_TRUE; 236 } 237 238 /* Implementation of gdb.selected_thread () -> gdb.InferiorThread. 239 Returns the selected thread object. */ 240 PyObject * 241 gdbpy_selected_thread (PyObject *self, PyObject *args) 242 { 243 PyObject *thread_obj; 244 245 thread_obj = (PyObject *) find_thread_object (inferior_ptid); 246 if (thread_obj) 247 { 248 Py_INCREF (thread_obj); 249 return thread_obj; 250 } 251 252 Py_RETURN_NONE; 253 } 254 255 256 257 void 258 gdbpy_initialize_thread (void) 259 { 260 if (PyType_Ready (&thread_object_type) < 0) 261 return; 262 263 Py_INCREF (&thread_object_type); 264 PyModule_AddObject (gdb_module, "InferiorThread", 265 (PyObject *) &thread_object_type); 266 } 267 268 269 270 static PyGetSetDef thread_object_getset[] = 271 { 272 { "name", thpy_get_name, thpy_set_name, 273 "The name of the thread, as set by the user or the OS.", NULL }, 274 { "num", thpy_get_num, NULL, "ID of the thread, as assigned by GDB.", NULL }, 275 { "ptid", thpy_get_ptid, NULL, "ID of the thread, as assigned by the OS.", 276 NULL }, 277 278 { NULL } 279 }; 280 281 static PyMethodDef thread_object_methods[] = 282 { 283 { "is_valid", thpy_is_valid, METH_NOARGS, 284 "is_valid () -> Boolean.\n\ 285 Return true if this inferior thread is valid, false if not." }, 286 { "switch", thpy_switch, METH_NOARGS, 287 "switch ()\n\ 288 Makes this the GDB selected thread." }, 289 { "is_stopped", thpy_is_stopped, METH_NOARGS, 290 "is_stopped () -> Boolean\n\ 291 Return whether the thread is stopped." }, 292 { "is_running", thpy_is_running, METH_NOARGS, 293 "is_running () -> Boolean\n\ 294 Return whether the thread is running." }, 295 { "is_exited", thpy_is_exited, METH_NOARGS, 296 "is_exited () -> Boolean\n\ 297 Return whether the thread is exited." }, 298 299 { NULL } 300 }; 301 302 static PyTypeObject thread_object_type = 303 { 304 PyVarObject_HEAD_INIT (NULL, 0) 305 "gdb.InferiorThread", /*tp_name*/ 306 sizeof (thread_object), /*tp_basicsize*/ 307 0, /*tp_itemsize*/ 308 thpy_dealloc, /*tp_dealloc*/ 309 0, /*tp_print*/ 310 0, /*tp_getattr*/ 311 0, /*tp_setattr*/ 312 0, /*tp_compare*/ 313 0, /*tp_repr*/ 314 0, /*tp_as_number*/ 315 0, /*tp_as_sequence*/ 316 0, /*tp_as_mapping*/ 317 0, /*tp_hash */ 318 0, /*tp_call*/ 319 0, /*tp_str*/ 320 0, /*tp_getattro*/ 321 0, /*tp_setattro*/ 322 0, /*tp_as_buffer*/ 323 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/ 324 "GDB thread object", /* tp_doc */ 325 0, /* tp_traverse */ 326 0, /* tp_clear */ 327 0, /* tp_richcompare */ 328 0, /* tp_weaklistoffset */ 329 0, /* tp_iter */ 330 0, /* tp_iternext */ 331 thread_object_methods, /* tp_methods */ 332 0, /* tp_members */ 333 thread_object_getset, /* tp_getset */ 334 0, /* tp_base */ 335 0, /* tp_dict */ 336 0, /* tp_descr_get */ 337 0, /* tp_descr_set */ 338 0, /* tp_dictoffset */ 339 0, /* tp_init */ 340 0 /* tp_alloc */ 341 }; 342