Modified Files:
[deliverable/binutils-gdb.git] / gdb / thread.c
CommitLineData
da0baf42
SG
1/* Multi-process/thread control for GDB, the GNU debugger.
2 Copyright 1986, 1987, 1988, 1993
3
4 Contributed by Lynx Real-Time Systems, Inc. Los Gatos, CA.
5 Free Software Foundation, Inc.
6
7This file is part of GDB.
8
9This program is free software; you can redistribute it and/or modify
10it under the terms of the GNU General Public License as published by
11the Free Software Foundation; either version 2 of the License, or
12(at your option) any later version.
13
14This program is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17GNU General Public License for more details.
18
19You should have received a copy of the GNU General Public License
20along with this program; if not, write to the Free Software
21Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
25286543
SG
22
23#include "defs.h"
24#include "symtab.h"
25#include "frame.h"
26#include "inferior.h"
27#include "environ.h"
28#include "value.h"
29#include "target.h"
30#include "thread.h"
46c28185 31#include "command.h"
25286543
SG
32
33#include <sys/types.h>
34#include <signal.h>
35
36/*#include "lynxos-core.h"*/
37
38struct thread_info
39{
40 struct thread_info *next;
41 int pid; /* Actual process id */
42 int num; /* Convenient handle */
43};
44
45static struct thread_info *thread_list = NULL;
46static int highest_thread_num;
47
25286543
SG
48static void thread_command PARAMS ((char * tidstr, int from_tty));
49
50static void prune_threads PARAMS ((void));
51
52static void thread_switch PARAMS ((int pid));
53
de43d7d0
SG
54static struct thread_info * find_thread_id PARAMS ((int num));
55
25286543
SG
56void
57init_thread_list ()
58{
59 struct thread_info *tp, *tpnext;
60
61 if (!thread_list)
62 return;
63
64 for (tp = thread_list; tp; tp = tpnext)
65 {
66 tpnext = tp->next;
67 free (tp);
68 }
69
70 thread_list = NULL;
71 highest_thread_num = 0;
72}
73
74void
75add_thread (pid)
76 int pid;
77{
78 struct thread_info *tp;
79
3082244d 80 tp = (struct thread_info *) xmalloc (sizeof (struct thread_info));
25286543
SG
81
82 tp->pid = pid;
83 tp->num = ++highest_thread_num;
84 tp->next = thread_list;
85 thread_list = tp;
86}
87
88static struct thread_info *
89find_thread_id (num)
90 int num;
91{
92 struct thread_info *tp;
93
94 for (tp = thread_list; tp; tp = tp->next)
95 if (tp->num == num)
96 return tp;
97
98 return NULL;
99}
100
de43d7d0
SG
101int
102valid_thread_id (num)
103 int num;
104{
105 struct thread_info *tp;
106
107 for (tp = thread_list; tp; tp = tp->next)
108 if (tp->num == num)
109 return 1;
110
111 return 0;
112}
113
114int
115pid_to_thread_id (pid)
116 int pid;
117{
118 struct thread_info *tp;
119
120 for (tp = thread_list; tp; tp = tp->next)
121 if (tp->pid == pid)
122 return tp->num;
123
124 return 0;
125}
126
25286543
SG
127int
128in_thread_list (pid)
129 int pid;
130{
131 struct thread_info *tp;
132
133 for (tp = thread_list; tp; tp = tp->next)
134 if (tp->pid == pid)
135 return 1;
136
137 return 0; /* Never heard of 'im */
138}
139
25286543
SG
140static void
141prune_threads ()
142{
143 struct thread_info *tp, *tpprev;
144
145 tpprev = 0;
146
147 for (tp = thread_list; tp; tp = tp->next)
148 if (tp->pid == -1)
149 {
150 if (tpprev)
151 tpprev->next = tp->next;
152 else
153 thread_list = NULL;
154
155 free (tp);
156 }
157 else
158 tpprev = tp;
159}
160
161/* Print information about currently known threads */
162
163static void
164info_threads_command (arg, from_tty)
165 char *arg;
166 int from_tty;
167{
168 struct thread_info *tp;
169 int current_pid = inferior_pid;
170
171 for (tp = thread_list; tp; tp = tp->next)
172 {
173 if (target_has_execution
174 && kill (tp->pid, 0) == -1)
175 {
46c28185 176 tp->pid = -1; /* Mark it as dead */
25286543
SG
177 continue;
178 }
179
180 if (tp->pid == current_pid)
181 printf_filtered ("* ");
182 else
183 printf_filtered (" ");
184
185 printf_filtered ("%d %s ", tp->num, target_pid_to_str (tp->pid));
186
187 thread_switch (tp->pid);
188 print_stack_frame (selected_frame, -1, 0);
189 }
190
191 thread_switch (current_pid);
192 prune_threads ();
193}
194
195/* Switch from one thread to another. */
196
3082244d 197static void
25286543
SG
198thread_switch (pid)
199 int pid;
200{
201 if (pid == inferior_pid)
202 return;
203
204 inferior_pid = pid;
25286543
SG
205 flush_cached_frames ();
206 registers_changed ();
207 stop_pc = read_pc();
208 set_current_frame (create_new_frame (read_fp (), stop_pc));
209 stop_frame_address = FRAME_FP (get_current_frame ());
210 select_frame (get_current_frame (), 0);
211}
212
5090e82c
SG
213static void
214restore_current_thread (pid)
215 int pid;
216{
217 if (pid != inferior_pid)
218 thread_switch (pid);
219}
220
221/* Apply a GDB command to a list of threads. List syntax is a whitespace
222 seperated list of numbers, or ranges, or the keyword `all'. Ranges consist
223 of two numbers seperated by a hyphen. Examples:
224
225 thread apply 1 2 7 4 backtrace Apply backtrace cmd to threads 1,2,7,4
226 thread apply 2-7 9 p foo(1) Apply p foo(1) cmd to threads 2->7 & 9
227 thread apply all p x/i $pc Apply x/i $pc cmd to all threads
228*/
229
230static void
231thread_apply_all_command (cmd, from_tty)
232 char *cmd;
233 int from_tty;
234{
235 struct thread_info *tp;
236 struct cleanup *old_chain;
237
238 if (cmd == NULL || *cmd == '\000')
239 error ("Please specify a command following the thread ID list");
240
241 old_chain = make_cleanup (restore_current_thread, inferior_pid);
242
243 for (tp = thread_list; tp; tp = tp->next)
244 {
245 thread_switch (tp->pid);
246 printf_filtered ("\nThread %d (%s):\n", tp->num,
247 target_pid_to_str (inferior_pid));
248 execute_command (cmd, from_tty);
249 }
250}
251
252static void
253thread_apply_command (tidlist, from_tty)
254 char *tidlist;
255 int from_tty;
256{
257 char *cmd;
258 char *p;
259 struct cleanup *old_chain;
260
261 if (tidlist == NULL || *tidlist == '\000')
262 error ("Please specify a thread ID list");
263
264 for (cmd = tidlist; *cmd != '\000' && !isalpha(*cmd); cmd++);
265
266 if (*cmd == '\000')
267 error ("Please specify a command following the thread ID list");
268
269 old_chain = make_cleanup (restore_current_thread, inferior_pid);
270
271 while (tidlist < cmd)
272 {
273 struct thread_info *tp;
274 int start, end;
275
276 start = strtol (tidlist, &p, 10);
277 if (p == tidlist)
278 error ("Error parsing %s", tidlist);
279 tidlist = p;
280
281 while (*tidlist == ' ' || *tidlist == '\t')
282 tidlist++;
283
284 if (*tidlist == '-') /* Got a range of IDs? */
285 {
286 tidlist++; /* Skip the - */
287 end = strtol (tidlist, &p, 10);
288 if (p == tidlist)
289 error ("Error parsing %s", tidlist);
290 tidlist = p;
291
292 while (*tidlist == ' ' || *tidlist == '\t')
293 tidlist++;
294 }
295 else
296 end = start;
297
298 for (; start <= end; start++)
299 {
300 tp = find_thread_id (start);
301
302 if (!tp)
303 {
304 warning ("Unknown thread %d.", start);
305 continue;
306 }
307
308 thread_switch (tp->pid);
309 printf_filtered ("\nThread %d (%s):\n", tp->num,
310 target_pid_to_str (inferior_pid));
311 execute_command (cmd, from_tty);
312 }
313 }
314}
315
316/* Switch to the specified thread. Will dispatch off to thread_apply_command
317 if prefix of arg is `apply'. */
318
25286543
SG
319static void
320thread_command (tidstr, from_tty)
321 char *tidstr;
322 int from_tty;
323{
324 int num;
325 struct thread_info *tp;
5090e82c 326 char *p;
25286543
SG
327
328 if (!tidstr)
329 error ("Please specify a thread ID. Use the \"info threads\" command to\n\
330see the IDs of currently known threads.");
331
25286543
SG
332 num = atoi (tidstr);
333
334 tp = find_thread_id (num);
335
336 if (!tp)
337 error ("Thread ID %d not known. Use the \"info threads\" command to\n\
338see the IDs of currently known threads.", num);
339
340 thread_switch (tp->pid);
341
342 printf_filtered ("[Switching to %s]\n", target_pid_to_str (inferior_pid));
343 print_stack_frame (selected_frame, selected_frame_level, 1);
344}
345
346void
347_initialize_thread ()
348{
5090e82c
SG
349 static struct cmd_list_element *thread_cmd_list = NULL;
350 static struct cmd_list_element *thread_apply_list = NULL;
351 extern struct cmd_list_element *cmdlist;
352
25286543
SG
353 add_info ("threads", info_threads_command,
354 "IDs of currently known threads.");
5090e82c
SG
355
356 add_prefix_cmd ("thread", class_run, thread_command,
357 "Use this command to switch between threads.\n\
358The new thread ID must be currently known.", &thread_cmd_list, "thread ", 1,
359 &cmdlist);
360
361 add_prefix_cmd ("apply", class_run, thread_apply_command,
362 "Apply a command to a list of threads.",
363 &thread_apply_list, "apply ", 1, &thread_cmd_list);
364
365 add_cmd ("all", class_run, thread_apply_all_command,
366 "Apply a command to all threads.",
367 &thread_apply_list);
368
369 add_com_alias ("t", "thread", class_run, 1);
25286543 370}
This page took 0.075761 seconds and 4 git commands to generate.