Sun Aug 1 22:58:18 1993 Stu Grossman (grossman at cygnus.com)
[external/binutils.git] / gdb / thread.c
1 /* for separate threads within the inferior process, for GDB.
2    Copyright (C) 1986, 1987, 1988 Free Software Foundation, Inc.
3
4 GDB is distributed in the hope that it will be useful, but WITHOUT ANY
5 WARRANTY.  No author or distributor accepts responsibility to anyone
6 for the consequences of using it or for whether it serves any
7 particular purpose or works at all, unless he says so in writing.
8 Refer to the GDB General Public License for full details.
9
10 Everyone is granted permission to copy, modify and redistribute GDB,
11 but only under the conditions described in the GDB General Public
12 License.  A copy of this license is supposed to have been given to you
13 along with GDB so you can know your rights and responsibilities.  It
14 should be in a file named COPYING.  Among other things, the copyright
15 notice and this notice must be preserved on all copies.
16
17 In other words, go ahead and share GDB, but don't try to stop
18 anyone else from sharing it farther.  Help stamp out software hoarding!
19 */
20
21 #include "defs.h"
22 #include "symtab.h"
23 #include "frame.h"
24 #include "inferior.h"
25 #include "environ.h"
26 #include "value.h"
27 #include "target.h"
28 #include "thread.h"
29
30 #include <sys/types.h>
31 #include <signal.h>
32
33 /*#include "lynxos-core.h"*/
34
35 struct thread_info
36 {
37   struct thread_info *next;
38   int pid;                      /* Actual process id */
39   int num;                      /* Convenient handle */
40 };
41
42 static struct thread_info *thread_list = NULL;
43 static int highest_thread_num;
44
45 static void thread_info PARAMS ((void));
46
47 static void thread_command PARAMS ((char * tidstr, int from_tty));
48
49 static void prune_threads PARAMS ((void));
50
51 static void thread_switch PARAMS ((int pid));
52
53 void
54 init_thread_list ()
55 {
56   struct thread_info *tp, *tpnext;
57
58   if (!thread_list)
59     return;
60
61   for (tp = thread_list; tp; tp = tpnext)
62     {
63       tpnext = tp->next;
64       free (tp);
65     }
66
67   thread_list = NULL;
68   highest_thread_num = 0;
69 }
70
71 void
72 add_thread (pid)
73      int pid;
74 {
75   struct thread_info *tp;
76
77   tp = xmalloc (sizeof (struct thread_info));
78
79   tp->pid = pid;
80   tp->num = ++highest_thread_num;
81   tp->next = thread_list;
82   thread_list = tp;
83 }
84
85 static struct thread_info *
86 find_thread_id (num)
87     int num;
88 {
89   struct thread_info *tp;
90
91   for (tp = thread_list; tp; tp = tp->next)
92     if (tp->num == num)
93       return tp;
94
95   return NULL;
96 }
97
98 int
99 in_thread_list (pid)
100     int pid;
101 {
102   struct thread_info *tp;
103
104   for (tp = thread_list; tp; tp = tp->next)
105     if (tp->pid == pid)
106       return 1;
107
108   return 0;                     /* Never heard of 'im */
109 }
110
111 #if 0
112 void
113 bfd_get_core_threads (abfd)
114     bfd *abfd;
115 {
116     int i;
117
118     inferior_pid = BUILDPID (inferior_pid, core_thread (abfd)->pid);
119     for (i = 0; i < core_pss (abfd).threadcnt; i++)
120       add_thread (core_thread (abfd)[i].pid);
121 }
122 #endif
123
124 static void
125 prune_threads ()
126 {
127   struct thread_info *tp, *tpprev;
128
129   tpprev = 0;
130
131   for (tp = thread_list; tp; tp = tp->next)
132     if (tp->pid == -1)
133       {
134         if (tpprev)
135           tpprev->next = tp->next;
136         else
137           thread_list = NULL;
138
139         free (tp);
140       }
141     else
142       tpprev = tp;
143 }
144
145 /* Print information about currently known threads */
146
147 static void
148 info_threads_command (arg, from_tty)
149      char *arg;
150      int from_tty;
151 {
152   struct thread_info *tp;
153   int current_pid = inferior_pid;
154
155   for (tp = thread_list; tp; tp = tp->next)
156     {
157       if (target_has_execution
158           && kill (tp->pid, 0) == -1)
159         {
160           tp->pid == -1;        /* Mark it as dead */
161           continue;
162         }
163
164       if (tp->pid == current_pid)
165         printf_filtered ("* ");
166       else
167         printf_filtered ("  ");
168
169       printf_filtered ("%d %s  ", tp->num, target_pid_to_str (tp->pid));
170
171       thread_switch (tp->pid);
172       print_stack_frame (selected_frame, -1, 0);
173     }
174
175   thread_switch (current_pid);
176   prune_threads ();
177 }
178
179 /* Switch from one thread to another. */
180
181 void
182 thread_switch (pid)
183      int pid;
184 {
185   if (pid == inferior_pid)
186     return;
187
188   inferior_pid = pid;
189   pc_changed = 0;
190   flush_cached_frames ();
191   registers_changed ();
192   stop_pc = read_pc();
193   set_current_frame (create_new_frame (read_fp (), stop_pc));
194   stop_frame_address = FRAME_FP (get_current_frame ());
195   select_frame (get_current_frame (), 0);
196 }
197
198 static void
199 thread_command (tidstr, from_tty)
200      char *tidstr;
201      int from_tty;
202 {
203   int num;
204   struct thread_info *tp;
205
206   if (!tidstr)
207     error ("Please specify a thread ID.  Use the \"info threads\" command to\n\
208 see the IDs of currently known threads.");
209
210
211   num = atoi (tidstr);
212
213   tp = find_thread_id (num);
214
215   if (!tp)
216     error ("Thread ID %d not known.  Use the \"info threads\" command to\n\
217 see the IDs of currently known threads.", num);
218
219   thread_switch (tp->pid);
220
221   printf_filtered ("[Switching to %s]\n", target_pid_to_str (inferior_pid));
222   print_stack_frame (selected_frame, selected_frame_level, 1);
223 }
224
225 void
226 _initialize_thread ()
227 {
228   add_info ("threads", info_threads_command,
229             "IDs of currently known threads.");
230   add_com ("thread", class_info, thread_command,
231            "Use this command to switch between threads.\n\
232 The new thread ID must be currently known.");
233 }