1/* Inferior process information for the remote server for GDB.
2   Copyright (C) 2002, 2005, 2011
3   Free Software Foundation, Inc.
4
5   Contributed by MontaVista Software.
6
7   This file is part of GDB.
8   It has been modified to integrate it in valgrind
9
10   This program is free software; you can redistribute it and/or modify
11   it under the terms of the GNU General Public License as published by
12   the Free Software Foundation; either version 2 of the License, or
13   (at your option) any later version.
14
15   This program is distributed in the hope that it will be useful,
16   but WITHOUT ANY WARRANTY; without even the implied warranty of
17   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18   GNU General Public License for more details.
19
20   You should have received a copy of the GNU General Public License
21   along with this program; if not, write to the Free Software
22   Foundation, Inc., 51 Franklin Street, Fifth Floor,
23   Boston, MA 02110-1301, USA.  */
24
25#include "server.h"
26
27struct thread_info
28{
29   struct inferior_list_entry entry;
30   void *target_data;
31   void *regcache_data;
32   unsigned int gdb_id;
33};
34
35struct inferior_list all_threads;
36
37struct thread_info *current_inferior;
38
39#define get_thread(inf) ((struct thread_info *)(inf))
40
41void add_inferior_to_list (struct inferior_list *list,
42		      struct inferior_list_entry *new_inferior)
43{
44   new_inferior->next = NULL;
45   if (list->tail != NULL)
46      list->tail->next = new_inferior;
47   else
48      list->head = new_inferior;
49   list->tail = new_inferior;
50}
51
52void for_each_inferior (struct inferior_list *list,
53		   void (*action) (struct inferior_list_entry *))
54{
55   struct inferior_list_entry *cur = list->head, *next;
56
57   while (cur != NULL) {
58      next = cur->next;
59      (*action) (cur);
60      cur = next;
61   }
62}
63
64void change_inferior_id (struct inferior_list *list,
65		    unsigned long new_id)
66{
67   if (list->head != list->tail)
68      error ("tried to change thread ID after multiple threads are created\n");
69
70   list->head->id = new_id;
71}
72
73void remove_inferior (struct inferior_list *list,
74		 struct inferior_list_entry *entry)
75{
76   struct inferior_list_entry **cur;
77
78   if (list->head == entry) {
79      list->head = entry->next;
80      if (list->tail == entry)
81         list->tail = list->head;
82      return;
83   }
84
85   cur = &list->head;
86   while (*cur && (*cur)->next != entry)
87      cur = &(*cur)->next;
88
89   if (*cur == NULL)
90      return;
91
92   (*cur)->next = entry->next;
93
94   if (list->tail == entry)
95      list->tail = *cur;
96}
97
98void add_thread (unsigned long thread_id, void *target_data, unsigned int gdb_id)
99{
100   struct thread_info *new_thread
101      = (struct thread_info *) malloc (sizeof (*new_thread));
102
103   VG_(memset) (new_thread, 0, sizeof (*new_thread));
104
105   new_thread->entry.id = thread_id;
106
107   add_inferior_to_list (&all_threads, & new_thread->entry);
108
109   if (current_inferior == NULL)
110      current_inferior = new_thread;
111
112   new_thread->target_data = target_data;
113   set_inferior_regcache_data (new_thread, new_register_cache ());
114   new_thread->gdb_id = gdb_id;
115}
116
117unsigned int thread_id_to_gdb_id (unsigned long thread_id)
118{
119   struct inferior_list_entry *inf = all_threads.head;
120
121   while (inf != NULL) {
122      struct thread_info *thread = get_thread (inf);
123      if (inf->id == thread_id)
124         return thread->gdb_id;
125      inf = inf->next;
126   }
127
128   return 0;
129}
130
131unsigned int thread_to_gdb_id (struct thread_info *thread)
132{
133   return thread->gdb_id;
134}
135
136struct thread_info * gdb_id_to_thread (unsigned int gdb_id)
137{
138   struct inferior_list_entry *inf = all_threads.head;
139
140   while (inf != NULL) {
141      struct thread_info *thread = get_thread (inf);
142      if (thread->gdb_id == gdb_id)
143         return thread;
144      inf = inf->next;
145   }
146
147   return NULL;
148}
149
150unsigned long gdb_id_to_thread_id (unsigned int gdb_id)
151{
152   struct thread_info *thread = gdb_id_to_thread (gdb_id);
153
154   return thread ? thread->entry.id : 0;
155}
156
157static
158void free_one_thread (struct inferior_list_entry *inf)
159{
160   struct thread_info *thread = get_thread (inf);
161   free_register_cache (inferior_regcache_data (thread));
162   free (thread);
163}
164
165void remove_thread (struct thread_info *thread)
166{
167   remove_inferior (&all_threads, (struct inferior_list_entry *) thread);
168   free_one_thread (&thread->entry);
169}
170
171void clear_inferiors (void)
172{
173   for_each_inferior (&all_threads, free_one_thread);
174
175   all_threads.head = all_threads.tail = NULL;
176}
177
178struct inferior_list_entry * find_inferior (struct inferior_list *list,
179                                            int (*func)
180                                              (struct inferior_list_entry *,
181                                               void *),
182                                            void *arg)
183{
184   struct inferior_list_entry *inf = list->head;
185
186   while (inf != NULL) {
187      if ((*func) (inf, arg))
188         return inf;
189      inf = inf->next;
190   }
191
192   return NULL;
193}
194
195struct inferior_list_entry * find_inferior_id (struct inferior_list *list,
196                                               unsigned long id)
197{
198   struct inferior_list_entry *inf = list->head;
199
200   while (inf != NULL) {
201      if (inf->id == id)
202         return inf;
203      inf = inf->next;
204   }
205
206   return NULL;
207}
208
209void * inferior_target_data (struct thread_info *inferior)
210{
211   return inferior->target_data;
212}
213
214void set_inferior_target_data (struct thread_info *inferior, void *data)
215{
216   inferior->target_data = data;
217}
218
219void * inferior_regcache_data (struct thread_info *inferior)
220{
221   return inferior->regcache_data;
222}
223
224void set_inferior_regcache_data (struct thread_info *inferior, void *data)
225{
226   inferior->regcache_data = data;
227}
228