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