1 /* Python interface to inferior threads. 2 3 Copyright (C) 2009-2015 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 "gdbthread.h" 22 #include "inferior.h" 23 #include "python-internal.h" 24 25 extern PyTypeObject thread_object_type 26 CPYCHECKER_TYPE_OBJECT_FOR_TYPEDEF ("thread_object"); 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 thread_object * 40 create_thread_object (struct thread_info *tp) 41 { 42 thread_object *thread_obj; 43 44 thread_obj = PyObject_New (thread_object, &thread_object_type); 45 if (!thread_obj) 46 return NULL; 47 48 thread_obj->thread = tp; 49 thread_obj->inf_obj = find_inferior_object (ptid_get_pid (tp->ptid)); 50 51 return thread_obj; 52 } 53 54 static void 55 thpy_dealloc (PyObject *self) 56 { 57 Py_DECREF (((thread_object *) self)->inf_obj); 58 Py_TYPE (self)->tp_free (self); 59 } 60 61 static PyObject * 62 thpy_get_name (PyObject *self, void *ignore) 63 { 64 thread_object *thread_obj = (thread_object *) self; 65 char *name; 66 67 THPY_REQUIRE_VALID (thread_obj); 68 69 name = thread_obj->thread->name; 70 if (name == NULL) 71 name = target_thread_name (thread_obj->thread); 72 73 if (name == NULL) 74 Py_RETURN_NONE; 75 76 return PyString_FromString (name); 77 } 78 79 static int 80 thpy_set_name (PyObject *self, PyObject *newvalue, void *ignore) 81 { 82 thread_object *thread_obj = (thread_object *) self; 83 char *name; 84 85 if (! thread_obj->thread) 86 { 87 PyErr_SetString (PyExc_RuntimeError, _("Thread no longer exists.")); 88 return -1; 89 } 90 91 if (newvalue == NULL) 92 { 93 PyErr_SetString (PyExc_TypeError, 94 _("Cannot delete `name' attribute.")); 95 return -1; 96 } 97 else if (newvalue == Py_None) 98 name = NULL; 99 else if (! gdbpy_is_string (newvalue)) 100 { 101 PyErr_SetString (PyExc_TypeError, 102 _("The value of `name' must be a string.")); 103 return -1; 104 } 105 else 106 { 107 name = python_string_to_host_string (newvalue); 108 if (! name) 109 return -1; 110 } 111 112 xfree (thread_obj->thread->name); 113 thread_obj->thread->name = name; 114 115 return 0; 116 } 117 118 static PyObject * 119 thpy_get_num (PyObject *self, void *closure) 120 { 121 thread_object *thread_obj = (thread_object *) self; 122 123 THPY_REQUIRE_VALID (thread_obj); 124 125 return PyLong_FromLong (thread_obj->thread->num); 126 } 127 128 /* Getter for InferiorThread.ptid -> (pid, lwp, tid). 129 Returns a tuple with the thread's ptid components. */ 130 131 static PyObject * 132 thpy_get_ptid (PyObject *self, void *closure) 133 { 134 int pid; 135 long tid, lwp; 136 thread_object *thread_obj = (thread_object *) self; 137 138 THPY_REQUIRE_VALID (thread_obj); 139 140 return gdbpy_create_ptid_object (thread_obj->thread->ptid); 141 } 142 143 /* Implementation of InferiorThread.switch (). 144 Makes this the GDB selected thread. */ 145 146 static PyObject * 147 thpy_switch (PyObject *self, PyObject *args) 148 { 149 thread_object *thread_obj = (thread_object *) self; 150 151 THPY_REQUIRE_VALID (thread_obj); 152 153 TRY 154 { 155 switch_to_thread (thread_obj->thread->ptid); 156 } 157 CATCH (except, RETURN_MASK_ALL) 158 { 159 GDB_PY_HANDLE_EXCEPTION (except); 160 } 161 END_CATCH 162 163 Py_RETURN_NONE; 164 } 165 166 /* Implementation of InferiorThread.is_stopped () -> Boolean. 167 Return whether the thread is stopped. */ 168 169 static PyObject * 170 thpy_is_stopped (PyObject *self, PyObject *args) 171 { 172 thread_object *thread_obj = (thread_object *) self; 173 174 THPY_REQUIRE_VALID (thread_obj); 175 176 if (is_stopped (thread_obj->thread->ptid)) 177 Py_RETURN_TRUE; 178 179 Py_RETURN_FALSE; 180 } 181 182 /* Implementation of InferiorThread.is_running () -> Boolean. 183 Return whether the thread is running. */ 184 185 static PyObject * 186 thpy_is_running (PyObject *self, PyObject *args) 187 { 188 thread_object *thread_obj = (thread_object *) self; 189 190 THPY_REQUIRE_VALID (thread_obj); 191 192 if (is_running (thread_obj->thread->ptid)) 193 Py_RETURN_TRUE; 194 195 Py_RETURN_FALSE; 196 } 197 198 /* Implementation of InferiorThread.is_exited () -> Boolean. 199 Return whether the thread is exited. */ 200 201 static PyObject * 202 thpy_is_exited (PyObject *self, PyObject *args) 203 { 204 thread_object *thread_obj = (thread_object *) self; 205 206 THPY_REQUIRE_VALID (thread_obj); 207 208 if (is_exited (thread_obj->thread->ptid)) 209 Py_RETURN_TRUE; 210 211 Py_RETURN_FALSE; 212 } 213 214 /* Implementation of gdb.InfThread.is_valid (self) -> Boolean. 215 Returns True if this inferior Thread object still exists 216 in GDB. */ 217 218 static PyObject * 219 thpy_is_valid (PyObject *self, PyObject *args) 220 { 221 thread_object *thread_obj = (thread_object *) self; 222 223 if (! thread_obj->thread) 224 Py_RETURN_FALSE; 225 226 Py_RETURN_TRUE; 227 } 228 229 /* Return a reference to a new Python object representing a ptid_t. 230 The object is a tuple containing (pid, lwp, tid). */ 231 PyObject * 232 gdbpy_create_ptid_object (ptid_t ptid) 233 { 234 int pid; 235 long tid, lwp; 236 PyObject *ret; 237 238 ret = PyTuple_New (3); 239 if (!ret) 240 return NULL; 241 242 pid = ptid_get_pid (ptid); 243 lwp = ptid_get_lwp (ptid); 244 tid = ptid_get_tid (ptid); 245 246 PyTuple_SET_ITEM (ret, 0, PyInt_FromLong (pid)); 247 PyTuple_SET_ITEM (ret, 1, PyInt_FromLong (lwp)); 248 PyTuple_SET_ITEM (ret, 2, PyInt_FromLong (tid)); 249 250 return ret; 251 } 252 253 /* Implementation of gdb.selected_thread () -> gdb.InferiorThread. 254 Returns the selected thread object. */ 255 256 PyObject * 257 gdbpy_selected_thread (PyObject *self, PyObject *args) 258 { 259 PyObject *thread_obj; 260 261 thread_obj = (PyObject *) find_thread_object (inferior_ptid); 262 if (thread_obj) 263 { 264 Py_INCREF (thread_obj); 265 return thread_obj; 266 } 267 268 Py_RETURN_NONE; 269 } 270 271 int 272 gdbpy_initialize_thread (void) 273 { 274 if (PyType_Ready (&thread_object_type) < 0) 275 return -1; 276 277 return gdb_pymodule_addobject (gdb_module, "InferiorThread", 278 (PyObject *) &thread_object_type); 279 } 280 281 static PyGetSetDef thread_object_getset[] = 282 { 283 { "name", thpy_get_name, thpy_set_name, 284 "The name of the thread, as set by the user or the OS.", NULL }, 285 { "num", thpy_get_num, NULL, "ID of the thread, as assigned by GDB.", NULL }, 286 { "ptid", thpy_get_ptid, NULL, "ID of the thread, as assigned by the OS.", 287 NULL }, 288 289 { NULL } 290 }; 291 292 static PyMethodDef thread_object_methods[] = 293 { 294 { "is_valid", thpy_is_valid, METH_NOARGS, 295 "is_valid () -> Boolean.\n\ 296 Return true if this inferior thread is valid, false if not." }, 297 { "switch", thpy_switch, METH_NOARGS, 298 "switch ()\n\ 299 Makes this the GDB selected thread." }, 300 { "is_stopped", thpy_is_stopped, METH_NOARGS, 301 "is_stopped () -> Boolean\n\ 302 Return whether the thread is stopped." }, 303 { "is_running", thpy_is_running, METH_NOARGS, 304 "is_running () -> Boolean\n\ 305 Return whether the thread is running." }, 306 { "is_exited", thpy_is_exited, METH_NOARGS, 307 "is_exited () -> Boolean\n\ 308 Return whether the thread is exited." }, 309 310 { NULL } 311 }; 312 313 PyTypeObject thread_object_type = 314 { 315 PyVarObject_HEAD_INIT (NULL, 0) 316 "gdb.InferiorThread", /*tp_name*/ 317 sizeof (thread_object), /*tp_basicsize*/ 318 0, /*tp_itemsize*/ 319 thpy_dealloc, /*tp_dealloc*/ 320 0, /*tp_print*/ 321 0, /*tp_getattr*/ 322 0, /*tp_setattr*/ 323 0, /*tp_compare*/ 324 0, /*tp_repr*/ 325 0, /*tp_as_number*/ 326 0, /*tp_as_sequence*/ 327 0, /*tp_as_mapping*/ 328 0, /*tp_hash */ 329 0, /*tp_call*/ 330 0, /*tp_str*/ 331 0, /*tp_getattro*/ 332 0, /*tp_setattro*/ 333 0, /*tp_as_buffer*/ 334 Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_ITER, /*tp_flags*/ 335 "GDB thread object", /* tp_doc */ 336 0, /* tp_traverse */ 337 0, /* tp_clear */ 338 0, /* tp_richcompare */ 339 0, /* tp_weaklistoffset */ 340 0, /* tp_iter */ 341 0, /* tp_iternext */ 342 thread_object_methods, /* tp_methods */ 343 0, /* tp_members */ 344 thread_object_getset, /* tp_getset */ 345 0, /* tp_base */ 346 0, /* tp_dict */ 347 0, /* tp_descr_get */ 348 0, /* tp_descr_set */ 349 0, /* tp_dictoffset */ 350 0, /* tp_init */ 351 0 /* tp_alloc */ 352 }; 353