2009-04-01 Pedro Alves <pedro@codesourcery.com>
authorPedro Alves <palves@redhat.com>
Wed, 1 Apr 2009 22:50:24 +0000 (22:50 +0000)
committerPedro Alves <palves@redhat.com>
Wed, 1 Apr 2009 22:50:24 +0000 (22:50 +0000)
Implement the multiprocess extensions, and add linux multiprocess
support.

* server.h (ULONGEST): Declare.
(struct ptid, ptid_t): New.
(minus_one_ptid, null_ptid): Declare.
(ptid_build, pid_to_ptid, ptid_get_pid, ptid_get_lwp)
(ptid_get_tid, ptid_equal, ptid_is_pid): Declare.
(struct inferior_list_entry): Change `id' type from unsigned from
to ptid_t.
(struct sym_cache, struct breakpoint, struct
process_info_private): Forward declare.
(struct process_info): Declare.
(current_process): Declare.
(all_processes): Declare.
(initialize_inferiors): Declare.
(add_thread): Adjust to use ptid_t.
(thread_id_to_gdb_id, thread_to_gdb_id, gdb_id_to_thread_id): Ditto.
(add_process, remove_process, find_thread_pid): Declare.
(find_inferior_id): Adjust to use ptid_t.
(cont_thread, general_thread, step_thread): Change type to ptid_t.
(multi_process): Declare.
(push_event): Adjust to use ptid_t.
(read_ptid, write_ptid): Declare.
(prepare_resume_reply): Adjust to use ptid_t.
(clear_symbol_cache): Declare.
* inferiors.c (all_processes): New.
(null_ptid, minus_one_ptid): New.
(ptid_build, pid_to_ptid, ptid_get_pid, ptid_get_lwp)
(ptid_get_tid, ptid_equal, ptid_is_pid): New.
(add_thread): Change unsigned long to ptid.  Remove gdb_id
parameter.  Adjust.
(thread_id_to_gdb_id, thread_to_gdb_id): Change unsigned long to ptid.
(gdb_id_to_thread): Rename to ...
(find_thread_pid): ... this.  Change unsigned long to ptid.
(gdb_id_to_thread_id, find_inferior_id): Change unsigned long to ptid.
(loaded_dll, pull_pid_from_list): Adjust.
(add_process, remove_process, find_process_pid)
(get_thread_process, current_process, initialize_inferiors): New.
* target.h (struct thread_resume) <thread>: Change type to ptid_t.
(struct target_waitstatus) <related_pid>: Ditto.
(struct target_ops) <kill, detach>: Add `pid' argument.  Change
return type to int.
(struct target_ops) <join>: Add `pid' argument.
(struct target_ops) <thread_alive>: Change pid's type to ptid_t.
(struct target_ops) <wait>: Add `ptid' field.  Change return type
to ptid.
(kill_inferior, detach_inferior, join_inferior): Add `pid' argument.
(mywait): Add `ptid' argument.  Change return type to ptid_t.
(target_pid_to_str): Declare.
* target.c (set_desired_inferior): Adjust to use ptids.
(mywait): Add new `ptid' argument.  Adjust.
(target_pid_to_str): New.
* mem-break.h (free_all_breakpoints): Declare.
* mem-break.c (breakpoints): Delelete.
(set_breakpoint_at, delete_breakpoint, find_breakpoint_at)
(check_mem_read, check_mem_write, delete_all_breakpoints): Adjust
to use per-process breakpoint list.
(free_all_breakpoints): New.
* remote-utils.c (struct sym_cache) <name>: Drop `const'.
(symbol_cache, all_symbols_looked_up): Delete.
(hexchars): New.
(ishex, unpack_varlen_hex, write_ptid, hex_or_minus_one,
read_ptid): New.
(prepare_resume_reply): Change ptid argument's type from unsigned
long to ptid_t.  Adjust.  Implement W;process and X;process.
(free_sym_cache, clear_symbol_cache): New.
(look_up_one_symbol): Adjust to per-process symbol cache.  *
* server.c (cont_thread, general_thread, step_thread): Change type
to ptid_t.
(attached): Delete.
(multi_process): New.
(last_ptid): Change type to ptid_t.
(struct vstop_notif) <ptid>: Change type to ptid_t.
(queue_stop_reply, push_event): Change `ptid' argument's type to
ptid_t.
(discard_queued_stop_replies): Add `pid' argument.
(start_inferior): Adjust to use ptids.  Adjust to mywait interface
changes.  Don't reference the `attached' global.
(attach_inferior): Adjust to mywait interface changes.
(handle_query): Adjust to use ptids.  Parse GDB's qSupported
features.  Handle and report "multiprocess+".  Handle
"qAttached:PID".
(handle_v_cont): Adjust to use ptids.  Adjust to mywait interface
changes.
(handle_v_kill): New.
(handle_v_stopped): Adjust to use target_pid_to_str.
(handle_v_requests): Allow multiple attaches and runs when
multiprocess extensions are in effect.  Handle "vKill".
(myresume): Adjust to use ptids.
(queue_stop_reply_callback): Add `arg' parameter.  Handle it.
(handle_status): Adjust to discard_queued_stop_replies interface
change.
(first_thread_of, kill_inferior_callback)
(detach_or_kill_inferior_callback, join_inferiors_callback): New.
(main): Call initialize_inferiors.  Adjust to use ptids, killing
and detaching from all inferiors.  Handle multiprocess packet
variants.
* linux-low.h: Include gdb_proc_service.h.
(struct process_info_private): New.
(struct linux_target_ops) <pid_of>: Use ptid_get_pid.
<lwpid_of>: Use ptid_get_lwp.
(get_lwp_thread): Adjust.
(struct lwp_info): Add `dead' member.
(find_lwp_pid): Declare.
* linux-low.c (thread_db_active): Delete.
(new_inferior): Adjust comment.
(inferior_pid): Delete.
(linux_add_process): New.
(handle_extended_wait): Adjust.
(add_lwp): Change unsigned long to ptid.
(linux_create_inferior): Add process to processes table.  Adjust
to use ptids.  Don't set new_inferior here.
(linux_attach_lwp): Rename to ...
(linux_attach_lwp_1): ... this.  Add `initial' argument.  Handle
it.  Adjust to use ptids.
(linux_attach_lwp): New.
(linux_attach): Add process to processes table.  Don't set
new_inferior here.
(struct counter): New.
(second_thread_of_pid_p, last_thread_of_process_p): New.
(linux_kill_one_lwp): Add `args' parameter.  Handle it.  Adjust to
multiple processes.
(linux_kill): Add `pid' argument.  Handle it.  Adjust to multiple
processes.  Remove process from process table.
(linux_detach_one_lwp): Add `args' parameter.  Handle it.  Adjust
to multiple processes.
(any_thread_of): New.
(linux_detach): Add `pid' argument, and handle it.  Remove process
from processes table.
(linux_join): Add `pid' argument.  Handle it.
(linux_thread_alive): Change unsighed long argument to ptid_t.
Consider dead lwps as not being alive.
(status_pending_p): Rename `dummy' argument to `arg'.  Filter out
threads we're not interested in.
(same_lwp, find_lwp_pid): New.
(linux_wait_for_lwp): Change `pid' argument's type from int to
ptid_t.  Adjust.
(linux_wait_for_event): Rename to ...
(linux_wait_for_event_1): ... this.  Change `pid' argument's type
from int to ptid_t.  Adjust.
(linux_wait_for_event): New.
(linux_wait_1): Add `ptid' argument.  Change return type to
ptid_t.  Adjust.  Use last_thread_of_process_p.  Remove processes
that exit from the process table.
(linux_wait): Add `ptid' argument.  Change return type to ptid_t.
Adjust.
(mark_lwp_dead): New.
(wait_for_sigstop): Adjust to use ptids.  If a process exits while
stopping all threads, mark its main lwp as dead.
(linux_set_resume_request, linux_resume_one_thread): Adjust to use
ptids.
(fetch_register, usr_store_inferior_registers)
(regsets_fetch_inferior_registers)
(regsets_store_inferior_registers, linux_read_memory)
(linux_write_memory): Inline `inferior_pid'.
(linux_look_up_symbols): Adjust to use per-process
`thread_db_active'.
(linux_request_interrupt): Adjust to use ptids.
(linux_read_auxv): Inline `inferior_pid'.
(initialize_low): Don't reference thread_db_active.
* gdb_proc_service.h (struct ps_prochandle) <pid>: Remove.
* proc-service.c (ps_lgetregs): Use find_lwp_pid.
(ps_getpid): Return the pid of the current inferior.
* thread-db.c (proc_handle, thread_agent): Delete.
(thread_db_create_event, thread_db_enable_reporting): Adjust to
per-process data.
(find_one_thread): Change argument type to ptid_t.  Adjust to
per-process data.
(maybe_attach_thread): Adjust to per-process data and ptids.
(thread_db_find_new_threads): Ditto.
(thread_db_init): Ditto.
* spu-low.c (spu_create_inferior, spu_attach): Add process to
processes table.  Adjust to use ptids.
(spu_kill, spu_detach): Adjust interface.  Remove process from
processes table.
(spu_join, spu_thread_alive): Adjust interface.
(spu_wait): Adjust interface.  Remove process from processes
table.  Adjust to use ptids.
* win32-low.c (current_inferior_tid): Delete.
(current_inferior_ptid): New.
(debug_event_ptid): New.
(thread_rec): Take a ptid.  Adjust.
(child_add_thread): Add `pid' argument.  Adjust to use ptids.
(child_delete_thread): Ditto.
(do_initial_child_stuff): Add `attached' argument.  Add process to
processes table.
(child_fetch_inferior_registers, child_store_inferior_registers):
Adjust.
(win32_create_inferior): Pass 0 to do_initial_child_stuff.
(win32_attach): Pass 1 to do_initial_child_stuff.
(win32_kill): Adjust interface.  Remove process from processes
table.
(win32_detach): Ditto.
(win32_join): Adjust interface.
(win32_thread_alive): Take a ptid.
(win32_resume): Adjust to use ptids.
(get_child_debug_event): Ditto.
(win32_wait): Adjust interface.  Remove exiting process from
processes table.

16 files changed:
gdb/gdbserver/ChangeLog
gdb/gdbserver/gdb_proc_service.h
gdb/gdbserver/inferiors.c
gdb/gdbserver/linux-low.c
gdb/gdbserver/linux-low.h
gdb/gdbserver/mem-break.c
gdb/gdbserver/mem-break.h
gdb/gdbserver/proc-service.c
gdb/gdbserver/remote-utils.c
gdb/gdbserver/server.c
gdb/gdbserver/server.h
gdb/gdbserver/spu-low.c
gdb/gdbserver/target.c
gdb/gdbserver/target.h
gdb/gdbserver/thread-db.c
gdb/gdbserver/win32-low.c

index a9bbf3a..6159aca 100644 (file)
@@ -1,5 +1,208 @@
 2009-04-01  Pedro Alves  <pedro@codesourcery.com>
 
+       Implement the multiprocess extensions, and add linux multiprocess
+       support.
+
+       * server.h (ULONGEST): Declare.
+       (struct ptid, ptid_t): New.
+       (minus_one_ptid, null_ptid): Declare.
+       (ptid_build, pid_to_ptid, ptid_get_pid, ptid_get_lwp)
+       (ptid_get_tid, ptid_equal, ptid_is_pid): Declare.
+       (struct inferior_list_entry): Change `id' type from unsigned from
+       to ptid_t.
+       (struct sym_cache, struct breakpoint, struct
+       process_info_private): Forward declare.
+       (struct process_info): Declare.
+       (current_process): Declare.
+       (all_processes): Declare.
+       (initialize_inferiors): Declare.
+       (add_thread): Adjust to use ptid_t.
+       (thread_id_to_gdb_id, thread_to_gdb_id, gdb_id_to_thread_id): Ditto.
+       (add_process, remove_process, find_thread_pid): Declare.
+       (find_inferior_id): Adjust to use ptid_t.
+       (cont_thread, general_thread, step_thread): Change type to ptid_t.
+       (multi_process): Declare.
+       (push_event): Adjust to use ptid_t.
+       (read_ptid, write_ptid): Declare.
+       (prepare_resume_reply): Adjust to use ptid_t.
+       (clear_symbol_cache): Declare.
+       * inferiors.c (all_processes): New.
+       (null_ptid, minus_one_ptid): New.
+       (ptid_build, pid_to_ptid, ptid_get_pid, ptid_get_lwp)
+       (ptid_get_tid, ptid_equal, ptid_is_pid): New.
+       (add_thread): Change unsigned long to ptid.  Remove gdb_id
+       parameter.  Adjust.
+       (thread_id_to_gdb_id, thread_to_gdb_id): Change unsigned long to ptid.
+       (gdb_id_to_thread): Rename to ...
+       (find_thread_pid): ... this.  Change unsigned long to ptid.
+       (gdb_id_to_thread_id, find_inferior_id): Change unsigned long to ptid.
+       (loaded_dll, pull_pid_from_list): Adjust.
+       (add_process, remove_process, find_process_pid)
+       (get_thread_process, current_process, initialize_inferiors): New.
+       * target.h (struct thread_resume) <thread>: Change type to ptid_t.
+       (struct target_waitstatus) <related_pid>: Ditto.
+       (struct target_ops) <kill, detach>: Add `pid' argument.  Change
+       return type to int.
+       (struct target_ops) <join>: Add `pid' argument.
+       (struct target_ops) <thread_alive>: Change pid's type to ptid_t.
+       (struct target_ops) <wait>: Add `ptid' field.  Change return type
+       to ptid.
+       (kill_inferior, detach_inferior, join_inferior): Add `pid' argument.
+       (mywait): Add `ptid' argument.  Change return type to ptid_t.
+       (target_pid_to_str): Declare.
+       * target.c (set_desired_inferior): Adjust to use ptids.
+       (mywait): Add new `ptid' argument.  Adjust.
+       (target_pid_to_str): New.
+       * mem-break.h (free_all_breakpoints): Declare.
+       * mem-break.c (breakpoints): Delelete.
+       (set_breakpoint_at, delete_breakpoint, find_breakpoint_at)
+       (check_mem_read, check_mem_write, delete_all_breakpoints): Adjust
+       to use per-process breakpoint list.
+       (free_all_breakpoints): New.
+       * remote-utils.c (struct sym_cache) <name>: Drop `const'.
+       (symbol_cache, all_symbols_looked_up): Delete.
+       (hexchars): New.
+       (ishex, unpack_varlen_hex, write_ptid, hex_or_minus_one,
+       read_ptid): New.
+       (prepare_resume_reply): Change ptid argument's type from unsigned
+       long to ptid_t.  Adjust.  Implement W;process and X;process.
+       (free_sym_cache, clear_symbol_cache): New.
+       (look_up_one_symbol): Adjust to per-process symbol cache.  *
+       * server.c (cont_thread, general_thread, step_thread): Change type
+       to ptid_t.
+       (attached): Delete.
+       (multi_process): New.
+       (last_ptid): Change type to ptid_t.
+       (struct vstop_notif) <ptid>: Change type to ptid_t.
+       (queue_stop_reply, push_event): Change `ptid' argument's type to
+       ptid_t.
+       (discard_queued_stop_replies): Add `pid' argument.
+       (start_inferior): Adjust to use ptids.  Adjust to mywait interface
+       changes.  Don't reference the `attached' global.
+       (attach_inferior): Adjust to mywait interface changes.
+       (handle_query): Adjust to use ptids.  Parse GDB's qSupported
+       features.  Handle and report "multiprocess+".  Handle
+       "qAttached:PID".
+       (handle_v_cont): Adjust to use ptids.  Adjust to mywait interface
+       changes.
+       (handle_v_kill): New.
+       (handle_v_stopped): Adjust to use target_pid_to_str.
+       (handle_v_requests): Allow multiple attaches and runs when
+       multiprocess extensions are in effect.  Handle "vKill".
+       (myresume): Adjust to use ptids.
+       (queue_stop_reply_callback): Add `arg' parameter.  Handle it.
+       (handle_status): Adjust to discard_queued_stop_replies interface
+       change.
+       (first_thread_of, kill_inferior_callback)
+       (detach_or_kill_inferior_callback, join_inferiors_callback): New.
+       (main): Call initialize_inferiors.  Adjust to use ptids, killing
+       and detaching from all inferiors.  Handle multiprocess packet
+       variants.
+       * linux-low.h: Include gdb_proc_service.h.
+       (struct process_info_private): New.
+       (struct linux_target_ops) <pid_of>: Use ptid_get_pid.
+       <lwpid_of>: Use ptid_get_lwp.
+       (get_lwp_thread): Adjust.
+       (struct lwp_info): Add `dead' member.
+       (find_lwp_pid): Declare.
+       * linux-low.c (thread_db_active): Delete.
+       (new_inferior): Adjust comment.
+       (inferior_pid): Delete.
+       (linux_add_process): New.
+       (handle_extended_wait): Adjust.
+       (add_lwp): Change unsigned long to ptid.
+       (linux_create_inferior): Add process to processes table.  Adjust
+       to use ptids.  Don't set new_inferior here.
+       (linux_attach_lwp): Rename to ...
+       (linux_attach_lwp_1): ... this.  Add `initial' argument.  Handle
+       it.  Adjust to use ptids.
+       (linux_attach_lwp): New.
+       (linux_attach): Add process to processes table.  Don't set
+       new_inferior here.
+       (struct counter): New.
+       (second_thread_of_pid_p, last_thread_of_process_p): New.
+       (linux_kill_one_lwp): Add `args' parameter.  Handle it.  Adjust to
+       multiple processes.
+       (linux_kill): Add `pid' argument.  Handle it.  Adjust to multiple
+       processes.  Remove process from process table.
+       (linux_detach_one_lwp): Add `args' parameter.  Handle it.  Adjust
+       to multiple processes.
+       (any_thread_of): New.
+       (linux_detach): Add `pid' argument, and handle it.  Remove process
+       from processes table.
+       (linux_join): Add `pid' argument.  Handle it.
+       (linux_thread_alive): Change unsighed long argument to ptid_t.
+       Consider dead lwps as not being alive.
+       (status_pending_p): Rename `dummy' argument to `arg'.  Filter out
+       threads we're not interested in.
+       (same_lwp, find_lwp_pid): New.
+       (linux_wait_for_lwp): Change `pid' argument's type from int to
+       ptid_t.  Adjust.
+       (linux_wait_for_event): Rename to ...
+       (linux_wait_for_event_1): ... this.  Change `pid' argument's type
+       from int to ptid_t.  Adjust.
+       (linux_wait_for_event): New.
+       (linux_wait_1): Add `ptid' argument.  Change return type to
+       ptid_t.  Adjust.  Use last_thread_of_process_p.  Remove processes
+       that exit from the process table.
+       (linux_wait): Add `ptid' argument.  Change return type to ptid_t.
+       Adjust.
+       (mark_lwp_dead): New.
+       (wait_for_sigstop): Adjust to use ptids.  If a process exits while
+       stopping all threads, mark its main lwp as dead.
+       (linux_set_resume_request, linux_resume_one_thread): Adjust to use
+       ptids.
+       (fetch_register, usr_store_inferior_registers)
+       (regsets_fetch_inferior_registers)
+       (regsets_store_inferior_registers, linux_read_memory)
+       (linux_write_memory): Inline `inferior_pid'.
+       (linux_look_up_symbols): Adjust to use per-process
+       `thread_db_active'.
+       (linux_request_interrupt): Adjust to use ptids.
+       (linux_read_auxv): Inline `inferior_pid'.
+       (initialize_low): Don't reference thread_db_active.
+       * gdb_proc_service.h (struct ps_prochandle) <pid>: Remove.
+       * proc-service.c (ps_lgetregs): Use find_lwp_pid.
+       (ps_getpid): Return the pid of the current inferior.
+       * thread-db.c (proc_handle, thread_agent): Delete.
+       (thread_db_create_event, thread_db_enable_reporting): Adjust to
+       per-process data.
+       (find_one_thread): Change argument type to ptid_t.  Adjust to
+       per-process data.
+       (maybe_attach_thread): Adjust to per-process data and ptids.
+       (thread_db_find_new_threads): Ditto.
+       (thread_db_init): Ditto.
+       * spu-low.c (spu_create_inferior, spu_attach): Add process to
+       processes table.  Adjust to use ptids.
+       (spu_kill, spu_detach): Adjust interface.  Remove process from
+       processes table.
+       (spu_join, spu_thread_alive): Adjust interface.
+       (spu_wait): Adjust interface.  Remove process from processes
+       table.  Adjust to use ptids.
+       * win32-low.c (current_inferior_tid): Delete.
+       (current_inferior_ptid): New.
+       (debug_event_ptid): New.
+       (thread_rec): Take a ptid.  Adjust.
+       (child_add_thread): Add `pid' argument.  Adjust to use ptids.
+       (child_delete_thread): Ditto.
+       (do_initial_child_stuff): Add `attached' argument.  Add process to
+       processes table.
+       (child_fetch_inferior_registers, child_store_inferior_registers):
+       Adjust.
+       (win32_create_inferior): Pass 0 to do_initial_child_stuff.
+       (win32_attach): Pass 1 to do_initial_child_stuff.
+       (win32_kill): Adjust interface.  Remove process from processes
+       table.
+       (win32_detach): Ditto.
+       (win32_join): Adjust interface.
+       (win32_thread_alive): Take a ptid.
+       (win32_resume): Adjust to use ptids.
+       (get_child_debug_event): Ditto.
+       (win32_wait): Adjust interface.  Remove exiting process from
+       processes table.
+
+2009-04-01  Pedro Alves  <pedro@codesourcery.com>
+
        Non-stop mode support.
 
        * server.h (non_stop): Declare.
index fc29f41..4d153e6 100644 (file)
@@ -66,8 +66,8 @@ typedef elf_gregset_t prgregset_t;
 /* Structure that identifies the target process.  */
 struct ps_prochandle
 {
-  /* The process id is all we need.  */
-  pid_t pid;
+  /* We don't need to track anything.  All context is served from the
+     current inferior.  */
 };
 
 #endif /* gdb_proc_service.h */
index 8ad64fa..2d26b6a 100644 (file)
@@ -30,12 +30,88 @@ struct thread_info
   unsigned int gdb_id;
 };
 
+struct inferior_list all_processes;
 struct inferior_list all_threads;
 struct inferior_list all_dlls;
 int dlls_changed;
 
 struct thread_info *current_inferior;
 
+
+/* Oft used ptids */
+ptid_t null_ptid;
+ptid_t minus_one_ptid;
+
+/* Create a ptid given the necessary PID, LWP, and TID components.  */
+
+ptid_t
+ptid_build (int pid, long lwp, long tid)
+{
+  ptid_t ptid;
+
+  ptid.pid = pid;
+  ptid.lwp = lwp;
+  ptid.tid = tid;
+  return ptid;
+}
+
+/* Create a ptid from just a pid.  */
+
+ptid_t
+pid_to_ptid (int pid)
+{
+  return ptid_build (pid, 0, 0);
+}
+
+/* Fetch the pid (process id) component from a ptid.  */
+
+int
+ptid_get_pid (ptid_t ptid)
+{
+  return ptid.pid;
+}
+
+/* Fetch the lwp (lightweight process) component from a ptid.  */
+
+long
+ptid_get_lwp (ptid_t ptid)
+{
+  return ptid.lwp;
+}
+
+/* Fetch the tid (thread id) component from a ptid.  */
+
+long
+ptid_get_tid (ptid_t ptid)
+{
+  return ptid.tid;
+}
+
+/* ptid_equal() is used to test equality of two ptids.  */
+
+int
+ptid_equal (ptid_t ptid1, ptid_t ptid2)
+{
+  return (ptid1.pid == ptid2.pid
+         && ptid1.lwp == ptid2.lwp
+         && ptid1.tid == ptid2.tid);
+}
+
+/* Return true if this ptid represents a process.  */
+
+int
+ptid_is_pid (ptid_t ptid)
+{
+  if (ptid_equal (minus_one_ptid, ptid))
+    return 0;
+  if (ptid_equal (null_ptid, ptid))
+    return 0;
+
+  return (ptid_get_pid (ptid) != 0
+         && ptid_get_lwp (ptid) == 0
+         && ptid_get_tid (ptid) == 0);
+}
+
 #define get_thread(inf) ((struct thread_info *)(inf))
 #define get_dll(inf) ((struct dll_info *)(inf))
 
@@ -93,7 +169,7 @@ remove_inferior (struct inferior_list *list,
 }
 
 void
-add_thread (unsigned long thread_id, void *target_data, unsigned int gdb_id)
+add_thread (ptid_t thread_id, void *target_data)
 {
   struct thread_info *new_thread = xmalloc (sizeof (*new_thread));
 
@@ -108,40 +184,38 @@ add_thread (unsigned long thread_id, void *target_data, unsigned int gdb_id)
 
   new_thread->target_data = target_data;
   set_inferior_regcache_data (new_thread, new_register_cache ());
-  new_thread->gdb_id = gdb_id;
 }
 
-unsigned int
-thread_id_to_gdb_id (unsigned long thread_id)
+ptid_t
+thread_id_to_gdb_id (ptid_t thread_id)
 {
   struct inferior_list_entry *inf = all_threads.head;
 
   while (inf != NULL)
     {
-      struct thread_info *thread = get_thread (inf);
-      if (inf->id == thread_id)
-       return thread->gdb_id;
+      if (ptid_equal (inf->id, thread_id))
+       return thread_id;
       inf = inf->next;
     }
 
-  return 0;
+  return null_ptid;
 }
 
-unsigned int
+ptid_t
 thread_to_gdb_id (struct thread_info *thread)
 {
-  return thread->gdb_id;
+  return thread->entry.id;
 }
 
 struct thread_info *
-gdb_id_to_thread (unsigned int gdb_id)
+find_thread_pid (ptid_t ptid)
 {
   struct inferior_list_entry *inf = all_threads.head;
 
   while (inf != NULL)
     {
       struct thread_info *thread = get_thread (inf);
-      if (thread->gdb_id == gdb_id)
+      if (ptid_equal (thread->entry.id, ptid))
        return thread;
       inf = inf->next;
     }
@@ -149,12 +223,12 @@ gdb_id_to_thread (unsigned int gdb_id)
   return NULL;
 }
 
-unsigned long
-gdb_id_to_thread_id (unsigned int gdb_id)
+ptid_t
+gdb_id_to_thread_id (ptid_t gdb_id)
 {
-  struct thread_info *thread = gdb_id_to_thread (gdb_id);
+  struct thread_info *thread = find_thread_pid (gdb_id);
 
-  return thread ? thread->entry.id : 0;
+  return thread ? thread->entry.id : null_ptid;
 }
 
 static void
@@ -192,13 +266,13 @@ find_inferior (struct inferior_list *list,
 }
 
 struct inferior_list_entry *
-find_inferior_id (struct inferior_list *list, unsigned long id)
+find_inferior_id (struct inferior_list *list, ptid_t id)
 {
   struct inferior_list_entry *inf = list->head;
 
   while (inf != NULL)
     {
-      if (inf->id == id)
+      if (ptid_equal (inf->id, id))
        return inf;
       inf = inf->next;
     }
@@ -267,7 +341,7 @@ loaded_dll (const char *name, CORE_ADDR base_addr)
   struct dll_info *new_dll = xmalloc (sizeof (*new_dll));
   memset (new_dll, 0, sizeof (*new_dll));
 
-  new_dll->entry.id = -1;
+  new_dll->entry.id = minus_one_ptid;
 
   new_dll->name = xstrdup (name);
   new_dll->base_addr = base_addr;
@@ -318,7 +392,7 @@ add_pid_to_list (struct inferior_list *list, unsigned long pid)
   struct inferior_list_entry *new_entry;
 
   new_entry = xmalloc (sizeof (struct inferior_list_entry));
-  new_entry->id = pid;
+  new_entry->id = pid_to_ptid (pid);
   add_inferior_to_list (list, new_entry);
 }
 
@@ -327,7 +401,7 @@ pull_pid_from_list (struct inferior_list *list, unsigned long pid)
 {
   struct inferior_list_entry *new_entry;
 
-  new_entry = find_inferior_id (list, pid);
+  new_entry = find_inferior_id (list, pid_to_ptid (pid));
   if (new_entry == NULL)
     return 0;
   else
@@ -337,3 +411,56 @@ pull_pid_from_list (struct inferior_list *list, unsigned long pid)
       return 1;
     }
 }
+
+struct process_info *
+add_process (int pid, int attached)
+{
+  struct process_info *process;
+
+  process = xcalloc (1, sizeof (*process));
+
+  process->head.id = pid_to_ptid (pid);
+  process->attached = attached;
+
+  add_inferior_to_list (&all_processes, &process->head);
+
+  return process;
+}
+
+void
+remove_process (struct process_info *process)
+{
+  clear_symbol_cache (&process->symbol_cache);
+  free_all_breakpoints (process);
+  remove_inferior (&all_processes, &process->head);
+}
+
+struct process_info *
+find_process_pid (int pid)
+{
+  return (struct process_info *)
+    find_inferior_id (&all_processes, pid_to_ptid (pid));
+}
+
+static struct process_info *
+get_thread_process (struct thread_info *thread)
+{
+  int pid = ptid_get_pid (thread->entry.id);
+  return find_process_pid (pid);
+}
+
+struct process_info *
+current_process (void)
+{
+  if (current_inferior == NULL)
+    fatal ("Current inferior requested, but current_inferior is NULL\n");
+
+  return get_thread_process (current_inferior);
+}
+
+void
+initialize_inferiors (void)
+{
+  null_ptid = ptid_build (0, 0, 0);
+  minus_one_ptid = ptid_build (-1, 0, 0);
+}
index ba1d7b4..eccc2e1 100644 (file)
    representation of the thread ID.
 
    ``all_lwps'' is keyed by the process ID - which on Linux is (presently)
-   the same as the LWP ID.  */
+   the same as the LWP ID.
+
+   ``all_processes'' is keyed by the "overall process ID", which
+   GNU/Linux calls tgid, "thread group ID".  */
 
 struct inferior_list all_lwps;
 
@@ -105,24 +108,28 @@ int stopping_threads;
 
 /* FIXME make into a target method?  */
 int using_threads = 1;
-static int thread_db_active;
 
 static int must_set_ptrace_flags;
 
-/* This flag is true iff we've just created or attached to a new inferior
-   but it has not stopped yet.  As soon as it does, we need to call the
-   low target's arch_setup callback.  */
+/* This flag is true iff we've just created or attached to our first
+   inferior but it has not stopped yet.  As soon as it does, we need
+   to call the low target's arch_setup callback.  Doing this only on
+   the first inferior avoids reinializing the architecture on every
+   inferior, and avoids messing with the register caches of the
+   already running inferiors.  NOTE: this assumes all inferiors under
+   control of gdbserver have the same architecture.  */
 static int new_inferior;
 
 static void linux_resume_one_lwp (struct inferior_list_entry *entry,
                                  int step, int signal, siginfo_t *info);
 static void linux_resume (struct thread_resume *resume_info, size_t n);
 static void stop_all_lwps (void);
-static int linux_wait_for_event (int pid, int *wstat, int options);
+static int linux_wait_for_event (ptid_t ptid, int *wstat, int options);
 static int check_removed_breakpoint (struct lwp_info *event_child);
-static void *add_lwp (unsigned long pid);
+static void *add_lwp (ptid_t ptid);
 static int my_waitpid (int pid, int *status, int flags);
 static int linux_stopped_by_watchpoint (void);
+static void mark_lwp_dead (struct lwp_info *lwp, int wstat);
 
 struct pending_signals
 {
@@ -139,9 +146,6 @@ static char *disabled_regsets;
 static int num_regsets;
 #endif
 
-/* FIXME: Delete eventually.  */
-#define inferior_pid (lwpid_of (get_thread_lwp (current_inferior)))
-
 /* The read/write ends of the pipe registered as waitable file in the
    event loop.  */
 static int linux_event_pipe[2] = { -1, -1 };
@@ -160,6 +164,24 @@ delete_lwp (struct lwp_info *lwp)
   free (lwp);
 }
 
+/* Add a process to the common process list, and set its private
+   data.  */
+
+static struct process_info *
+linux_add_process (int pid, int attached)
+{
+  struct process_info *proc;
+
+  /* Is this the first process?  If so, then set the arch.  */
+  if (all_processes.head == NULL)
+    new_inferior = 1;
+
+  proc = add_process (pid, attached);
+  proc->private = xcalloc (1, sizeof (*proc->private));
+
+  return proc;
+}
+
 /* Handle a GNU/Linux extended wait response.  If we see a clone
    event, we need to add the new LWP to our list (and not report the
    trap to higher layers).  */
@@ -172,6 +194,7 @@ handle_extended_wait (struct lwp_info *event_child, int wstat)
 
   if (event == PTRACE_EVENT_CLONE)
     {
+      ptid_t ptid;
       unsigned long new_pid;
       int ret, status = W_STOPCODE (SIGSTOP);
 
@@ -195,9 +218,9 @@ handle_extended_wait (struct lwp_info *event_child, int wstat)
 
       ptrace (PTRACE_SETOPTIONS, new_pid, 0, PTRACE_O_TRACECLONE);
 
-      new_lwp = (struct lwp_info *) add_lwp (new_pid);
-      add_thread (new_pid, new_lwp, new_pid);
-      new_thread_notify (thread_id_to_gdb_id (lwpid_of (new_lwp)));
+      ptid = ptid_build (pid_of (event_child), new_pid, 0);
+      new_lwp = (struct lwp_info *) add_lwp (ptid);
+      add_thread (ptid, new_lwp);
 
       /* Normally we will get the pending SIGSTOP.  But in some cases
         we might get another signal delivered to the group first.
@@ -266,14 +289,14 @@ get_stop_pc (void)
 }
 
 static void *
-add_lwp (unsigned long pid)
+add_lwp (ptid_t ptid)
 {
   struct lwp_info *lwp;
 
   lwp = (struct lwp_info *) xmalloc (sizeof (*lwp));
   memset (lwp, 0, sizeof (*lwp));
 
-  lwp->head.id = pid;
+  lwp->head.id = ptid;
 
   add_inferior_to_list (&all_lwps, &lwp->head);
 
@@ -288,6 +311,7 @@ linux_create_inferior (char *program, char **allargs)
 {
   void *new_lwp;
   int pid;
+  ptid_t ptid;
 
 #if defined(__UCLIBC__) && defined(HAS_NOMMU)
   pid = vfork ();
@@ -315,44 +339,58 @@ linux_create_inferior (char *program, char **allargs)
       _exit (0177);
     }
 
-  new_lwp = add_lwp (pid);
-  add_thread (pid, new_lwp, pid);
+  linux_add_process (pid, 0);
+
+  ptid = ptid_build (pid, pid, 0);
+  new_lwp = add_lwp (ptid);
+  add_thread (ptid, new_lwp);
   must_set_ptrace_flags = 1;
-  new_inferior = 1;
 
   return pid;
 }
 
 /* Attach to an inferior process.  */
 
-void
-linux_attach_lwp (unsigned long pid)
+static void
+linux_attach_lwp_1 (unsigned long lwpid, int initial)
 {
+  ptid_t ptid;
   struct lwp_info *new_lwp;
 
-  if (ptrace (PTRACE_ATTACH, pid, 0, 0) != 0)
+  if (ptrace (PTRACE_ATTACH, lwpid, 0, 0) != 0)
     {
-      if (all_threads.head != NULL)
+      if (!initial)
        {
          /* If we fail to attach to an LWP, just warn.  */
-         fprintf (stderr, "Cannot attach to lwp %ld: %s (%d)\n", pid,
+         fprintf (stderr, "Cannot attach to lwp %ld: %s (%d)\n", lwpid,
                   strerror (errno), errno);
          fflush (stderr);
          return;
        }
       else
        /* If we fail to attach to a process, report an error.  */
-       error ("Cannot attach to lwp %ld: %s (%d)\n", pid,
+       error ("Cannot attach to lwp %ld: %s (%d)\n", lwpid,
               strerror (errno), errno);
     }
 
   /* FIXME: This intermittently fails.
      We need to wait for SIGSTOP first.  */
-  ptrace (PTRACE_SETOPTIONS, pid, 0, PTRACE_O_TRACECLONE);
+  ptrace (PTRACE_SETOPTIONS, lwpid, 0, PTRACE_O_TRACECLONE);
+
+  if (initial)
+    /* NOTE/FIXME: This lwp might have not been the tgid.  */
+    ptid = ptid_build (lwpid, lwpid, 0);
+  else
+    {
+      /* Note that extracting the pid from the current inferior is
+        safe, since we're always called in the context of the same
+        process as this new thread.  */
+      int pid = pid_of (get_thread_lwp (current_inferior));
+      ptid = ptid_build (pid, lwpid, 0);
+    }
 
-  new_lwp = (struct lwp_info *) add_lwp (pid);
-  add_thread (pid, new_lwp, pid);
-  new_thread_notify (thread_id_to_gdb_id (lwpid_of (new_lwp)));
+  new_lwp = (struct lwp_info *) add_lwp (ptid);
+  add_thread (ptid, new_lwp);
 
   /* The next time we wait for this LWP we'll see a SIGSTOP as PTRACE_ATTACH
      brings it to a halt.
@@ -389,42 +427,89 @@ linux_attach_lwp (unsigned long pid)
     new_lwp->stop_expected = 1;
 }
 
+void
+linux_attach_lwp (unsigned long lwpid)
+{
+  linux_attach_lwp_1 (lwpid, 0);
+}
+
 int
 linux_attach (unsigned long pid)
 {
   struct lwp_info *lwp;
 
-  linux_attach_lwp (pid);
+  linux_attach_lwp_1 (pid, 1);
+
+  linux_add_process (pid, 1);
 
   if (!non_stop)
     {
       /* Don't ignore the initial SIGSTOP if we just attached to this
         process.  It will be collected by wait shortly.  */
-      lwp = (struct lwp_info *) find_inferior_id (&all_lwps, pid);
+      lwp = (struct lwp_info *) find_inferior_id (&all_lwps,
+                                                 ptid_build (pid, pid, 0));
       lwp->stop_expected = 0;
     }
 
-  new_inferior = 1;
+  return 0;
+}
+
+struct counter
+{
+  int pid;
+  int count;
+};
+
+static int
+second_thread_of_pid_p (struct inferior_list_entry *entry, void *args)
+{
+  struct counter *counter = args;
+
+  if (ptid_get_pid (entry->id) == counter->pid)
+    {
+      if (++counter->count > 1)
+       return 1;
+    }
 
   return 0;
 }
 
-/* Kill the inferior process.  Make us have no inferior.  */
+static int
+last_thread_of_process_p (struct thread_info *thread)
+{
+  ptid_t ptid = ((struct inferior_list_entry *)thread)->id;
+  int pid = ptid_get_pid (ptid);
+  struct counter counter = { pid , 0 };
 
-static void
-linux_kill_one_lwp (struct inferior_list_entry *entry)
+  return (find_inferior (&all_threads,
+                        second_thread_of_pid_p, &counter) == NULL);
+}
+
+/* Kill the inferior lwp.  */
+
+static int
+linux_kill_one_lwp (struct inferior_list_entry *entry, void *args)
 {
   struct thread_info *thread = (struct thread_info *) entry;
   struct lwp_info *lwp = get_thread_lwp (thread);
-  int pid;
   int wstat;
+  int pid = * (int *) args;
+
+  if (ptid_get_pid (entry->id) != pid)
+    return 0;
 
   /* We avoid killing the first thread here, because of a Linux kernel (at
      least 2.6.0-test7 through 2.6.8-rc4) bug; if we kill the parent before
      the children get a chance to be reaped, it will remain a zombie
      forever.  */
-  if (entry == all_threads.head)
-    return;
+
+  if (last_thread_of_process_p (thread))
+    {
+      if (debug_threads)
+       fprintf (stderr, "lkop: is last of process %s\n",
+                target_pid_to_str (entry->id));
+      return 0;
+    }
 
   /* If we're killing a running inferior, make sure it is stopped
      first, as PTRACE_KILL will not work otherwise.  */
@@ -436,29 +521,35 @@ linux_kill_one_lwp (struct inferior_list_entry *entry)
       ptrace (PTRACE_KILL, lwpid_of (lwp), 0, 0);
 
       /* Make sure it died.  The loop is most likely unnecessary.  */
-      pid = linux_wait_for_event (lwpid_of (lwp), &wstat, __WALL);
+      pid = linux_wait_for_event (lwp->head.id, &wstat, __WALL);
     } while (pid > 0 && WIFSTOPPED (wstat));
+
+  return 0;
 }
 
-static void
-linux_kill (void)
+static int
+linux_kill (int pid)
 {
-  struct thread_info *thread = (struct thread_info *) all_threads.head;
+  struct process_info *process;
   struct lwp_info *lwp;
+  struct thread_info *thread;
   int wstat;
-  int pid;
+  int lwpid;
 
-  if (thread == NULL)
-    return;
+  process = find_process_pid (pid);
+  if (process == NULL)
+    return -1;
 
-  for_each_inferior (&all_threads, linux_kill_one_lwp);
+  find_inferior (&all_threads, linux_kill_one_lwp, &pid);
 
   /* See the comment in linux_kill_one_lwp.  We did not kill the first
      thread in the list, so do so now.  */
-  lwp = get_thread_lwp (thread);
+  lwp = find_lwp_pid (pid_to_ptid (pid));
+  thread = get_lwp_thread (lwp);
 
   if (debug_threads)
-    fprintf (stderr, "lk_1: killing lwp %ld\n", lwpid_of (lwp));
+    fprintf (stderr, "lk_1: killing lwp %ld, for pid: %d\n",
+            lwpid_of (lwp), pid);
 
   /* If we're killing a running inferior, make sure it is stopped
      first, as PTRACE_KILL will not work otherwise.  */
@@ -470,24 +561,29 @@ linux_kill (void)
       ptrace (PTRACE_KILL, lwpid_of (lwp), 0, 0);
 
       /* Make sure it died.  The loop is most likely unnecessary.  */
-      pid = linux_wait_for_event (lwpid_of (lwp), &wstat, __WALL);
-    } while (pid > 0 && WIFSTOPPED (wstat));
+      lwpid = linux_wait_for_event (lwp->head.id, &wstat, __WALL);
+    } while (lwpid > 0 && WIFSTOPPED (wstat));
 
   delete_lwp (lwp);
-  clear_inferiors ();
+  remove_process (process);
+  return 0;
 }
 
-static void
-linux_detach_one_lwp (struct inferior_list_entry *entry)
+static int
+linux_detach_one_lwp (struct inferior_list_entry *entry, void *args)
 {
   struct thread_info *thread = (struct thread_info *) entry;
   struct lwp_info *lwp = get_thread_lwp (thread);
+  int pid = * (int *) args;
+
+  if (ptid_get_pid (entry->id) != pid)
+    return 0;
 
   /* If we're detaching from a running inferior, make sure it is
      stopped first, as PTRACE_DETACH will not work otherwise.  */
   if (!lwp->stopped)
     {
-      int pid = lwpid_of (lwp);
+      int lwpid = lwpid_of (lwp);
 
       stopping_threads = 1;
       send_sigstop (&lwp->head);
@@ -500,9 +596,9 @@ linux_detach_one_lwp (struct inferior_list_entry *entry)
 
       /* If LWP exits while we're trying to stop it, there's nothing
         left to do.  */
-      lwp = (struct lwp_info *) find_inferior_id (&all_lwps, pid);
+      lwp = find_lwp_pid (pid_to_ptid (lwpid));
       if (lwp == NULL)
-       return;
+       return 0;
     }
 
   /* Make sure the process isn't stopped at a breakpoint that's
@@ -519,7 +615,7 @@ linux_detach_one_lwp (struct inferior_list_entry *entry)
       lwp->stop_expected = 0;
       if (lwp->stopped)
        linux_resume_one_lwp (&lwp->head, 0, 0, NULL);
-      linux_wait_for_event (lwpid_of (lwp), &wstat, __WALL);
+      linux_wait_for_event (lwp->head.id, &wstat, __WALL);
     }
 
   /* Flush any pending changes to the process's registers.  */
@@ -530,29 +626,50 @@ linux_detach_one_lwp (struct inferior_list_entry *entry)
   ptrace (PTRACE_DETACH, lwpid_of (lwp), 0, 0);
 
   delete_lwp (lwp);
+  return 0;
 }
 
 static int
-linux_detach (void)
+any_thread_of (struct inferior_list_entry *entry, void *args)
 {
+  int *pid_p = args;
+
+  if (ptid_get_pid (entry->id) == *pid_p)
+    return 1;
+
+  return 0;
+}
+
+static int
+linux_detach (int pid)
+{
+  struct process_info *process;
+
+  process = find_process_pid (pid);
+  if (process == NULL)
+    return -1;
+
+  current_inferior =
+    (struct thread_info *) find_inferior (&all_threads, any_thread_of, &pid);
+
   delete_all_breakpoints ();
-  for_each_inferior (&all_threads, linux_detach_one_lwp);
-  clear_inferiors ();
+  find_inferior (&all_threads, linux_detach_one_lwp, &pid);
+  remove_process (process);
   return 0;
 }
 
 static void
-linux_join (void)
+linux_join (int pid)
 {
   int status, ret;
-  struct thread_info *thread;
-  struct lwp_info *lwp;
+  struct process_info *process;
 
-  thread = (struct thread_info *) all_threads.head;
-  lwp = get_thread_lwp (thread);
+  process = find_process_pid (pid);
+  if (process == NULL)
+    return;
 
   do {
-    ret = my_waitpid (lwpid_of (lwp), &status, 0);
+    ret = my_waitpid (pid, &status, 0);
     if (WIFEXITED (status) || WIFSIGNALED (status))
       break;
   } while (ret != -1 || errno != ECHILD);
@@ -560,10 +677,15 @@ linux_join (void)
 
 /* Return nonzero if the given thread is still alive.  */
 static int
-linux_thread_alive (unsigned long lwpid)
+linux_thread_alive (ptid_t ptid)
 {
-  if (find_inferior_id (&all_threads, lwpid) != NULL)
-    return 1;
+  struct lwp_info *lwp = find_lwp_pid (ptid);
+
+  /* We assume we always know if a thread exits.  If a whole process
+     exited but we still haven't been able to report it to GDB, we'll
+     hold on to the last lwp of the dead process.  */
+  if (lwp != NULL)
+    return !lwp->dead;
   else
     return 0;
 }
@@ -633,9 +755,16 @@ check_removed_breakpoint (struct lwp_info *event_child)
 /* Return 1 if this lwp has an interesting status pending.  This
    function may silently resume an inferior lwp.  */
 static int
-status_pending_p (struct inferior_list_entry *entry, void *dummy)
+status_pending_p (struct inferior_list_entry *entry, void *arg)
 {
   struct lwp_info *lwp = (struct lwp_info *) entry;
+  ptid_t ptid = * (ptid_t *) arg;
+
+  /* Check if we're only interested in events from a specific process
+     or its lwps.  */
+  if (!ptid_equal (minus_one_ptid, ptid)
+      && ptid_get_pid (ptid) != ptid_get_pid (lwp->head.id))
+    return 0;
 
   if (lwp->status_pending_p && !lwp->suspended)
     if (check_removed_breakpoint (lwp))
@@ -653,15 +782,43 @@ status_pending_p (struct inferior_list_entry *entry, void *dummy)
   return (lwp->status_pending_p && !lwp->suspended);
 }
 
+static int
+same_lwp (struct inferior_list_entry *entry, void *data)
+{
+  ptid_t ptid = *(ptid_t *) data;
+  int lwp;
+
+  if (ptid_get_lwp (ptid) != 0)
+    lwp = ptid_get_lwp (ptid);
+  else
+    lwp = ptid_get_pid (ptid);
+
+  if (ptid_get_lwp (entry->id) == lwp)
+    return 1;
+
+  return 0;
+}
+
+struct lwp_info *
+find_lwp_pid (ptid_t ptid)
+{
+  return (struct lwp_info*) find_inferior (&all_lwps, same_lwp, &ptid);
+}
+
 static struct lwp_info *
-linux_wait_for_lwp (int pid, int *wstatp, int options)
+linux_wait_for_lwp (ptid_t ptid, int *wstatp, int options)
 {
   int ret;
-  int to_wait_for = pid;
+  int to_wait_for = -1;
   struct lwp_info *child = NULL;
 
   if (debug_threads)
-    fprintf (stderr, "linux_wait_for_lwp: %d\n", pid);
+    fprintf (stderr, "linux_wait_for_lwp: %s\n", target_pid_to_str (ptid));
+
+  if (ptid_equal (ptid, minus_one_ptid))
+    to_wait_for = -1;                  /* any child */
+  else
+    to_wait_for = ptid_get_lwp (ptid); /* this lwp only */
 
   options |= __WALL;
 
@@ -679,7 +836,7 @@ retry:
              && WSTOPSIG (*wstatp) != 33)))
     fprintf (stderr, "Got an event from %d (%x)\n", ret, *wstatp);
 
-  child = (struct lwp_info *) find_inferior_id (&all_lwps, ret);
+  child = find_lwp_pid (pid_to_ptid (ret));
 
   /* If we didn't find a process, one of two things presumably happened:
      - A process we started and then detached from has exited.  Ignore it.
@@ -716,7 +873,7 @@ retry:
     {
       struct thread_info *saved_inferior = current_inferior;
       current_inferior = (struct thread_info *)
-       find_inferior_id (&all_threads, lwpid_of (child));
+       find_inferior_id (&all_threads, child->head.id);
       /* For testing only; i386_stop_pc prints out a diagnostic.  */
       if (the_low_target.get_pc != NULL)
        get_stop_pc ();
@@ -733,29 +890,29 @@ retry:
    the stopped child otherwise.  */
 
 static int
-linux_wait_for_event (int pid, int *wstat, int options)
+linux_wait_for_event_1 (ptid_t ptid, int *wstat, int options)
 {
   CORE_ADDR stop_pc;
   struct lwp_info *event_child = NULL;
   int bp_status;
   struct lwp_info *requested_child = NULL;
 
-  /* Check for a process with a pending status.  */
+  /* Check for a lwp with a pending status.  */
   /* It is possible that the user changed the pending task's registers since
      it stopped.  We correctly handle the change of PC if we hit a breakpoint
      (in check_removed_breakpoint); signals should be reported anyway.  */
 
-  if (pid == -1)
+  if (ptid_equal (ptid, minus_one_ptid)
+      || ptid_equal (pid_to_ptid (ptid_get_pid (ptid)), ptid))
     {
       event_child = (struct lwp_info *)
-       find_inferior (&all_lwps, status_pending_p, NULL);
+       find_inferior (&all_lwps, status_pending_p, &ptid);
       if (debug_threads && event_child)
        fprintf (stderr, "Got a pending child %ld\n", lwpid_of (event_child));
     }
   else
     {
-      requested_child = (struct lwp_info *)
-       find_inferior_id (&all_lwps, pid);
+      requested_child = find_lwp_pid (ptid);
       if (requested_child->status_pending_p
          && !check_removed_breakpoint (requested_child))
        event_child = requested_child;
@@ -779,7 +936,7 @@ linux_wait_for_event (int pid, int *wstat, int options)
      events.  */
   while (1)
     {
-      event_child = linux_wait_for_lwp (pid, wstat, options);
+      event_child = linux_wait_for_lwp (ptid, wstat, options);
 
       if ((options & WNOHANG) && event_child == NULL)
        return 0;
@@ -792,19 +949,18 @@ linux_wait_for_event (int pid, int *wstat, int options)
       /* Check for thread exit.  */
       if (! WIFSTOPPED (*wstat))
        {
-         int lwpid = lwpid_of (event_child);
          if (debug_threads)
-           fprintf (stderr, "LWP %d exiting\n", lwpid);
+           fprintf (stderr, "LWP %ld exiting\n", lwpid_of (event_child));
 
          /* If the last thread is exiting, just return.  */
-         if (all_threads.head == all_threads.tail)
+         if (last_thread_of_process_p (current_inferior))
            {
              if (debug_threads)
-               fprintf (stderr, "LWP %d is last lwp of process\n", lwpid);
+               fprintf (stderr, "LWP %ld is last lwp of process\n",
+                        lwpid_of (event_child));
              return lwpid_of (event_child);
            }
 
-         dead_thread_notify (thread_id_to_gdb_id (lwpid_of (event_child)));
          delete_lwp (event_child);
 
          if (!non_stop)
@@ -824,7 +980,7 @@ linux_wait_for_event (int pid, int *wstat, int options)
          /* If we were waiting for this particular child to do something...
             well, it did something.  */
          if (requested_child != NULL)
-           return lwpid;
+           return lwpid_of (event_child);
 
          /* Wait for a more interesting event.  */
          continue;
@@ -862,7 +1018,7 @@ linux_wait_for_event (int pid, int *wstat, int options)
          && !event_child->stepping
          && (
 #ifdef USE_THREAD_DB
-             (thread_db_active
+             (current_process ()->private->thread_db_active
               && (WSTOPSIG (*wstat) == __SIGRTMIN
                   || WSTOPSIG (*wstat) == __SIGRTMIN + 1))
              ||
@@ -1000,16 +1156,56 @@ linux_wait_for_event (int pid, int *wstat, int options)
   return 0;
 }
 
+static int
+linux_wait_for_event (ptid_t ptid, int *wstat, int options)
+{
+  ptid_t wait_ptid;
+
+  if (ptid_is_pid (ptid))
+    {
+      /* A request to wait for a specific tgid.  This is not possible
+        with waitpid, so instead, we wait for any child, and leave
+        children we're not interested in right now with a pending
+        status to report later.  */
+      wait_ptid = minus_one_ptid;
+    }
+  else
+    wait_ptid = ptid;
+
+  while (1)
+    {
+      int event_pid;
+
+      event_pid = linux_wait_for_event_1 (wait_ptid, wstat, options);
+
+      if (event_pid > 0
+         && ptid_is_pid (ptid) && ptid_get_pid (ptid) != event_pid)
+       {
+         struct lwp_info *event_child = find_lwp_pid (pid_to_ptid (event_pid));
+
+         if (! WIFSTOPPED (*wstat))
+           mark_lwp_dead (event_child, *wstat);
+         else
+           {
+             event_child->status_pending_p = 1;
+             event_child->status_pending = *wstat;
+           }
+       }
+      else
+       return event_pid;
+    }
+}
+
 /* Wait for process, returns status.  */
 
-static unsigned long
-linux_wait_1 (struct target_waitstatus *ourstatus, int target_options)
+static ptid_t
+linux_wait_1 (ptid_t ptid,
+             struct target_waitstatus *ourstatus, int target_options)
 {
   int w;
   struct thread_info *thread = NULL;
   struct lwp_info *lwp = NULL;
   int options;
-  int wait_pid = -1;
   int pid;
 
   /* Translate generic target options into linux options.  */
@@ -1026,7 +1222,9 @@ retry:
      then we need to make sure we restart the other threads.  We could
      pick a thread at random or restart all; restarting all is less
      arbitrary.  */
-  if (!non_stop && cont_thread != 0 && cont_thread != -1)
+  if (!non_stop
+      && !ptid_equal (cont_thread, null_ptid)
+      && !ptid_equal (cont_thread, minus_one_ptid))
     {
       thread = (struct thread_info *) find_inferior_id (&all_threads,
                                                        cont_thread);
@@ -1035,18 +1233,18 @@ retry:
       if (thread == NULL)
        {
          struct thread_resume resume_info;
-         resume_info.thread = -1;
+         resume_info.thread = minus_one_ptid;
          resume_info.kind = resume_continue;
          resume_info.sig = 0;
          linux_resume (&resume_info, 1);
        }
       else
-       wait_pid = cont_thread;
+       ptid = cont_thread;
     }
 
-  pid = linux_wait_for_event (wait_pid, &w, options);
+  pid = linux_wait_for_event (ptid, &w, options);
   if (pid == 0) /* only if TARGET_WNOHANG */
-    return pid;
+    return null_ptid;
 
   lwp = get_thread_lwp (current_inferior);
 
@@ -1067,16 +1265,15 @@ retry:
      Report the exit status of the last thread to exit.  This matches
      LinuxThreads' behavior.  */
 
-  if (all_threads.head == all_threads.tail)
+  if (last_thread_of_process_p (current_inferior))
     {
       if (WIFEXITED (w) || WIFSIGNALED (w))
        {
-         int pid;
-
-         pid = pid_of (lwp);
+         int pid = pid_of (lwp);
+         struct process_info *process = find_process_pid (pid);
 
          delete_lwp (lwp);
-         clear_inferiors ();
+         remove_process (process);
 
          current_inferior = NULL;
 
@@ -1098,7 +1295,7 @@ retry:
 
            }
 
-         return pid;
+         return pid_to_ptid (pid);
        }
     }
   else
@@ -1135,12 +1332,12 @@ retry:
     }
 
   if (debug_threads)
-    fprintf (stderr, "linux_wait ret = %ld, %d, %d\n",
-            lwpid_of (lwp),
+    fprintf (stderr, "linux_wait ret = %s, %d, %d\n",
+            target_pid_to_str (lwp->head.id),
             ourstatus->kind,
             ourstatus->value.sig);
 
-  return lwpid_of (lwp);
+  return lwp->head.id;
 }
 
 /* Get rid of any pending event in the pipe.  */
@@ -1171,25 +1368,26 @@ async_file_mark (void)
      be awakened anyway.  */
 }
 
-static unsigned long
-linux_wait (struct target_waitstatus *ourstatus, int target_options)
+static ptid_t
+linux_wait (ptid_t ptid,
+           struct target_waitstatus *ourstatus, int target_options)
 {
-  unsigned long event_ptid;
+  ptid_t event_ptid;
 
   if (debug_threads)
-    fprintf (stderr, "linux_wait\n");
+    fprintf (stderr, "linux_wait: [%s]\n", target_pid_to_str (ptid));
 
   /* Flush the async file first.  */
   if (target_is_async_p ())
     async_file_flush ();
 
-  event_ptid = linux_wait_1 (ourstatus, target_options);
+  event_ptid = linux_wait_1 (ptid, ourstatus, target_options);
 
   /* If at least one stop was reported, there may be more.  A single
      SIGCHLD can signal more than one child stop.  */
   if (target_is_async_p ()
       && (target_options & TARGET_WNOHANG) != 0
-      && event_ptid != 0)
+      && !ptid_equal (event_ptid, null_ptid))
     async_file_mark ();
 
   return event_ptid;
@@ -1251,13 +1449,34 @@ send_sigstop (struct inferior_list_entry *entry)
 }
 
 static void
+mark_lwp_dead (struct lwp_info *lwp, int wstat)
+{
+  /* It's dead, really.  */
+  lwp->dead = 1;
+
+  /* Store the exit status for later.  */
+  lwp->status_pending_p = 1;
+  lwp->status_pending = wstat;
+
+  /* So that check_removed_breakpoint doesn't try to figure out if
+     this is stopped at a breakpoint.  */
+  lwp->pending_is_breakpoint = 0;
+
+  /* Prevent trying to stop it.  */
+  lwp->stopped = 1;
+
+  /* No further stops are expected from a dead lwp.  */
+  lwp->stop_expected = 0;
+}
+
+static void
 wait_for_sigstop (struct inferior_list_entry *entry)
 {
   struct lwp_info *lwp = (struct lwp_info *) entry;
   struct thread_info *saved_inferior;
   int wstat;
-  unsigned long saved_tid;
-  unsigned long ptid;
+  ptid_t saved_tid;
+  ptid_t ptid;
 
   if (lwp->stopped)
     return;
@@ -1266,9 +1485,9 @@ wait_for_sigstop (struct inferior_list_entry *entry)
   if (saved_inferior != NULL)
     saved_tid = ((struct inferior_list_entry *) saved_inferior)->id;
   else
-    saved_tid = 0; /* avoid bogus unused warning */
+    saved_tid = null_ptid; /* avoid bogus unused warning */
 
-  ptid = lwpid_of (lwp);
+  ptid = lwp->head.id;
 
   linux_wait_for_event (ptid, &wstat, __WALL);
 
@@ -1301,6 +1520,18 @@ wait_for_sigstop (struct inferior_list_entry *entry)
        }
       lwp->stop_expected = 1;
     }
+  else if (!WIFSTOPPED (wstat))
+    {
+      if (debug_threads)
+       fprintf (stderr, "Process %ld exited while stopping LWPs\n",
+                lwpid_of (lwp));
+
+      /* Leave this status pending for the next time we're able to
+        report it.  In the mean time, we'll report this lwp as dead
+        to GDB, so GDB doesn't try to read registers and memory from
+        it.  */
+      mark_lwp_dead (lwp, wstat);
+    }
 
   if (saved_inferior == NULL || linux_thread_alive (saved_tid))
     current_inferior = saved_inferior;
@@ -1474,11 +1705,19 @@ linux_set_resume_request (struct inferior_list_entry *entry, void *arg)
   r = arg;
 
   for (ndx = 0; ndx < r->n; ndx++)
-    if (r->resume[ndx].thread == -1 || r->resume[ndx].thread == entry->id)
-      {
-       lwp->resume = &r->resume[ndx];
-       return 0;
-      }
+    {
+      ptid_t ptid = r->resume[ndx].thread;
+      if (ptid_equal (ptid, minus_one_ptid)
+         || ptid_equal (ptid, entry->id)
+         || (ptid_is_pid (ptid)
+             && (ptid_get_pid (ptid) == pid_of (lwp)))
+         || (ptid_get_lwp (ptid) == -1
+             && (ptid_get_pid (ptid) == pid_of (lwp))))
+       {
+         lwp->resume = &r->resume[ndx];
+         return 0;
+       }
+    }
 
   /* No resume action for this thread.  */
   lwp->resume = NULL;
@@ -1550,7 +1789,7 @@ linux_resume_one_thread (struct inferior_list_entry *entry, void *arg)
       if (!lwp->stopped)
        {
          if (debug_threads)
-           fprintf (stderr, "running -> suspending %ld\n", lwpid_of (lwp));
+           fprintf (stderr, "running -> suspending LWP %ld\n", lwpid_of (lwp));
 
          lwp->suspended = 1;
          send_sigstop (&lwp->head);
@@ -1596,7 +1835,7 @@ linux_resume_one_thread (struct inferior_list_entry *entry, void *arg)
       if (debug_threads)
        fprintf (stderr, "resuming LWP %ld\n", lwpid_of (lwp));
 
-      if (lwp->resume->thread == -1
+      if (ptid_equal (lwp->resume->thread, minus_one_ptid)
          && lwp->stepping
          && lwp->pending_is_breakpoint)
        step = 1;
@@ -1685,6 +1924,7 @@ fetch_register (int regno)
   CORE_ADDR regaddr;
   int i, size;
   char *buf;
+  int pid;
 
   if (regno >= the_low_target.num_regs)
     return;
@@ -1694,6 +1934,8 @@ fetch_register (int regno)
   regaddr = register_addr (regno);
   if (regaddr == -1)
     return;
+
+  pid = lwpid_of (get_thread_lwp (current_inferior));
   size = ((register_size (regno) + sizeof (PTRACE_XFER_TYPE) - 1)
          & - sizeof (PTRACE_XFER_TYPE));
   buf = alloca (size);
@@ -1701,7 +1943,7 @@ fetch_register (int regno)
     {
       errno = 0;
       *(PTRACE_XFER_TYPE *) (buf + i) =
-       ptrace (PTRACE_PEEKUSER, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, 0);
+       ptrace (PTRACE_PEEKUSER, pid, (PTRACE_ARG3_TYPE) regaddr, 0);
       regaddr += sizeof (PTRACE_XFER_TYPE);
       if (errno != 0)
        {
@@ -1766,10 +2008,11 @@ usr_store_inferior_registers (int regno)
       else
        collect_register (regno, buf);
 
+      pid = lwpid_of (get_thread_lwp (current_inferior));
       for (i = 0; i < size; i += sizeof (PTRACE_XFER_TYPE))
        {
          errno = 0;
-         ptrace (PTRACE_POKEUSER, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
+         ptrace (PTRACE_POKEUSER, pid, (PTRACE_ARG3_TYPE) regaddr,
                  *(PTRACE_XFER_TYPE *) (buf + i));
          if (errno != 0)
            {
@@ -1808,9 +2051,11 @@ regsets_fetch_inferior_registers ()
 {
   struct regset_info *regset;
   int saw_general_regs = 0;
+  int pid;
 
   regset = target_regsets;
 
+  pid = lwpid_of (get_thread_lwp (current_inferior));
   while (regset->size >= 0)
     {
       void *buf;
@@ -1824,9 +2069,9 @@ regsets_fetch_inferior_registers ()
 
       buf = xmalloc (regset->size);
 #ifndef __sparc__
-      res = ptrace (regset->get_request, inferior_pid, 0, buf);
+      res = ptrace (regset->get_request, pid, 0, buf);
 #else
-      res = ptrace (regset->get_request, inferior_pid, buf, 0);
+      res = ptrace (regset->get_request, pid, buf, 0);
 #endif
       if (res < 0)
        {
@@ -1840,8 +2085,8 @@ regsets_fetch_inferior_registers ()
          else
            {
              char s[256];
-             sprintf (s, "ptrace(regsets_fetch_inferior_registers) PID=%ld",
-                      inferior_pid);
+             sprintf (s, "ptrace(regsets_fetch_inferior_registers) PID=%d",
+                      pid);
              perror (s);
            }
        }
@@ -1861,9 +2106,11 @@ regsets_store_inferior_registers ()
 {
   struct regset_info *regset;
   int saw_general_regs = 0;
+  int pid;
 
   regset = target_regsets;
 
+  pid = lwpid_of (get_thread_lwp (current_inferior));
   while (regset->size >= 0)
     {
       void *buf;
@@ -1881,9 +2128,9 @@ regsets_store_inferior_registers ()
         in case there are any items in the kernel's regset that are
         not in gdbserver's regcache.  */
 #ifndef __sparc__
-      res = ptrace (regset->get_request, inferior_pid, 0, buf);
+      res = ptrace (regset->get_request, pid, 0, buf);
 #else
-      res = ptrace (regset->get_request, inferior_pid, buf, 0);
+      res = ptrace (regset->get_request, pid, buf, 0);
 #endif
 
       if (res == 0)
@@ -1893,9 +2140,9 @@ regsets_store_inferior_registers ()
 
          /* Only now do we write the register set.  */
 #ifndef __sparc__
-         res = ptrace (regset->set_request, inferior_pid, 0, buf);
+         res = ptrace (regset->set_request, pid, 0, buf);
 #else
-         res = ptrace (regset->set_request, inferior_pid, buf, 0);
+         res = ptrace (regset->set_request, pid, buf, 0);
 #endif
        }
 
@@ -1979,13 +2226,14 @@ linux_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
     = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE));
   int fd;
   char filename[64];
+  int pid = lwpid_of (get_thread_lwp (current_inferior));
 
   /* Try using /proc.  Don't bother for one word.  */
   if (len >= 3 * sizeof (long))
     {
       /* We could keep this file open and cache it - possibly one per
         thread.  That requires some juggling, but is even faster.  */
-      sprintf (filename, "/proc/%ld/mem", inferior_pid);
+      sprintf (filename, "/proc/%d/mem", pid);
       fd = open (filename, O_RDONLY | O_LARGEFILE);
       if (fd == -1)
        goto no_proc;
@@ -2013,8 +2261,7 @@ linux_read_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len)
   for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
     {
       errno = 0;
-      buffer[i] = ptrace (PTRACE_PEEKTEXT, inferior_pid,
-                         (PTRACE_ARG3_TYPE) addr, 0);
+      buffer[i] = ptrace (PTRACE_PEEKTEXT, pid, (PTRACE_ARG3_TYPE) addr, 0);
       if (errno)
        return errno;
     }
@@ -2043,6 +2290,7 @@ linux_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
   = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1) / sizeof (PTRACE_XFER_TYPE);
   /* Allocate buffer of that many longwords.  */
   register PTRACE_XFER_TYPE *buffer = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE));
+  int pid = lwpid_of (get_thread_lwp (current_inferior));
 
   if (debug_threads)
     {
@@ -2051,13 +2299,12 @@ linux_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
 
   /* Fill start and end extra bytes of buffer with existing memory data.  */
 
-  buffer[0] = ptrace (PTRACE_PEEKTEXT, inferior_pid,
-                     (PTRACE_ARG3_TYPE) addr, 0);
+  buffer[0] = ptrace (PTRACE_PEEKTEXT, pid, (PTRACE_ARG3_TYPE) addr, 0);
 
   if (count > 1)
     {
       buffer[count - 1]
-       = ptrace (PTRACE_PEEKTEXT, inferior_pid,
+       = ptrace (PTRACE_PEEKTEXT, pid,
                  (PTRACE_ARG3_TYPE) (addr + (count - 1)
                                      * sizeof (PTRACE_XFER_TYPE)),
                  0);
@@ -2072,7 +2319,7 @@ linux_write_memory (CORE_ADDR memaddr, const unsigned char *myaddr, int len)
   for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
     {
       errno = 0;
-      ptrace (PTRACE_POKETEXT, inferior_pid, (PTRACE_ARG3_TYPE) addr, buffer[i]);
+      ptrace (PTRACE_POKETEXT, pid, (PTRACE_ARG3_TYPE) addr, buffer[i]);
       if (errno)
        return errno;
     }
@@ -2278,10 +2525,13 @@ static void
 linux_look_up_symbols (void)
 {
 #ifdef USE_THREAD_DB
-  if (thread_db_active)
+  struct process_info *proc = current_process ();
+
+  if (proc->private->thread_db_active)
     return;
 
-  thread_db_active = thread_db_init (!linux_supports_tracefork_flag);
+  proc->private->thread_db_active
+    = thread_db_init (!linux_supports_tracefork_flag);
 #endif
 }
 
@@ -2290,7 +2540,8 @@ linux_request_interrupt (void)
 {
   extern unsigned long signal_pid;
 
-  if (cont_thread != 0 && cont_thread != -1)
+  if (!ptid_equal (cont_thread, null_ptid)
+      && !ptid_equal (cont_thread, minus_one_ptid))
     {
       struct lwp_info *lwp;
       int lwpid;
@@ -2311,8 +2562,9 @@ linux_read_auxv (CORE_ADDR offset, unsigned char *myaddr, unsigned int len)
 {
   char filename[PATH_MAX];
   int fd, n;
+  int pid = lwpid_of (get_thread_lwp (current_inferior));
 
-  snprintf (filename, sizeof filename, "/proc/%ld/auxv", inferior_pid);
+  snprintf (filename, sizeof filename, "/proc/%d/auxv", pid);
 
   fd = open (filename, O_RDONLY);
   if (fd < 0)
@@ -2685,7 +2937,6 @@ initialize_low (void)
 {
   struct sigaction sigchld_action;
   memset (&sigchld_action, 0, sizeof (sigchld_action));
-  thread_db_active = 0;
   set_target_ops (&linux_target_ops);
   set_breakpoint_data (the_low_target.breakpoint,
                       the_low_target.breakpoint_len);
index 7818452..b076c5d 100644 (file)
@@ -21,6 +21,8 @@
 #include <thread_db.h>
 #endif
 
+#include "gdb_proc_service.h"
+
 #ifdef HAVE_LINUX_REGSETS
 typedef void (*regset_fill_func) (void *);
 typedef void (*regset_store_func) (const void *);
@@ -41,6 +43,19 @@ struct regset_info
 extern struct regset_info target_regsets[];
 #endif
 
+struct process_info_private
+{
+  /* True if this process has loaded thread_db, and it is active.  */
+  int thread_db_active;
+
+  /* Structure that identifies the child process for the
+     <proc_service.h> interface.  */
+  struct ps_prochandle proc_handle;
+
+  /* Connection to the libthread_db library.  */
+  td_thragent_t *thread_agent;
+};
+
 struct linux_target_ops
 {
   /* Architecture-specific setup.  */
@@ -78,14 +93,14 @@ struct linux_target_ops
 
 extern struct linux_target_ops the_low_target;
 
-#define pid_of(proc) ((proc)->head.id)
-#define lwpid_of(proc) ((proc)->head.id)
+#define pid_of(proc) ptid_get_pid ((proc)->head.id)
+#define lwpid_of(proc) ptid_get_lwp ((proc)->head.id)
 
 #define get_lwp(inf) ((struct lwp_info *)(inf))
 #define get_thread_lwp(thr) (get_lwp (inferior_target_data (thr)))
 #define get_lwp_thread(proc) ((struct thread_info *)                   \
                              find_inferior_id (&all_threads,           \
-                                               lwpid_of (get_lwp (proc))))
+                                               get_lwp (proc)->head.id))
 
 struct lwp_info
 {
@@ -106,6 +121,11 @@ struct lwp_info
      event already received in a wait()).  */
   int stopped;
 
+  /* If this flag is set, the lwp is known to be dead already (exit
+     event already received in a wait(), and is cached in
+     status_pending).  */
+  int dead;
+
   /* When stopped is set, the last wait status recorded for this lwp.  */
   int last_status;
 
@@ -150,3 +170,5 @@ void linux_attach_lwp (unsigned long pid);
 int thread_db_init (int use_events);
 int thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset,
                               CORE_ADDR load_module, CORE_ADDR *address);
+
+struct lwp_info *find_lwp_pid (ptid_t ptid);
index 8c0c05a..9d89326 100644 (file)
@@ -46,11 +46,10 @@ struct breakpoint
   int (*handler) (CORE_ADDR);
 };
 
-struct breakpoint *breakpoints;
-
 void
 set_breakpoint_at (CORE_ADDR where, int (*handler) (CORE_ADDR))
 {
+  struct process_info *proc = current_process ();
   struct breakpoint *bp;
 
   if (breakpoint_data == NULL)
@@ -67,24 +66,25 @@ set_breakpoint_at (CORE_ADDR where, int (*handler) (CORE_ADDR))
   bp->pc = where;
   bp->handler = handler;
 
-  bp->next = breakpoints;
-  breakpoints = bp;
+  bp->next = proc->breakpoints;
+  proc->breakpoints = bp;
 }
 
 static void
 delete_breakpoint (struct breakpoint *bp)
 {
+  struct process_info *proc = current_process ();
   struct breakpoint *cur;
 
-  if (breakpoints == bp)
+  if (proc->breakpoints == bp)
     {
-      breakpoints = bp->next;
+      proc->breakpoints = bp->next;
       (*the_target->write_memory) (bp->pc, bp->old_data,
                                   breakpoint_len);
       free (bp);
       return;
     }
-  cur = breakpoints;
+  cur = proc->breakpoints;
   while (cur->next)
     {
       if (cur->next == bp)
@@ -102,7 +102,8 @@ delete_breakpoint (struct breakpoint *bp)
 static struct breakpoint *
 find_breakpoint_at (CORE_ADDR where)
 {
-  struct breakpoint *bp = breakpoints;
+  struct process_info *proc = current_process ();
+  struct breakpoint *bp = proc->breakpoints;
 
   while (bp != NULL)
     {
@@ -225,7 +226,8 @@ set_breakpoint_data (const unsigned char *bp_data, int bp_len)
 void
 check_mem_read (CORE_ADDR mem_addr, unsigned char *buf, int mem_len)
 {
-  struct breakpoint *bp = breakpoints;
+  struct process_info *proc = current_process ();
+  struct breakpoint *bp = proc->breakpoints;
   CORE_ADDR mem_end = mem_addr + mem_len;
 
   for (; bp != NULL; bp = bp->next)
@@ -258,7 +260,8 @@ check_mem_read (CORE_ADDR mem_addr, unsigned char *buf, int mem_len)
 void
 check_mem_write (CORE_ADDR mem_addr, unsigned char *buf, int mem_len)
 {
-  struct breakpoint *bp = breakpoints;
+  struct process_info *proc = current_process ();
+  struct breakpoint *bp = proc->breakpoints;
   CORE_ADDR mem_end = mem_addr + mem_len;
 
   for (; bp != NULL; bp = bp->next)
@@ -290,11 +293,29 @@ check_mem_write (CORE_ADDR mem_addr, unsigned char *buf, int mem_len)
     }
 }
 
-/* Delete all breakpoints.  */
+/* Delete all breakpoints, and un-insert them from the inferior.  */
 
 void
 delete_all_breakpoints (void)
 {
-  while (breakpoints)
-    delete_breakpoint (breakpoints);
+  struct process_info *proc = current_process ();
+
+  while (proc->breakpoints)
+    delete_breakpoint (proc->breakpoints);
+}
+
+/* Release all breakpoints, but do not try to un-insert them from the
+   inferior.  */
+
+void
+free_all_breakpoints (struct process_info *proc)
+{
+  struct breakpoint *bp;
+
+  while (proc->breakpoints)
+    {
+      bp = proc->breakpoints;
+      proc->breakpoints = bp->next;
+      free (bp);
+    }
 }
index e7272a1..87afe3d 100644 (file)
@@ -75,4 +75,9 @@ void set_breakpoint_data (const unsigned char *bp_data, int bp_len);
 
 void delete_all_breakpoints (void);
 
+/* Delete all breakpoints, but do not try to un-insert them from the
+   inferior.  */
+
+void free_all_breakpoints (struct process_info *proc);
+
 #endif /* MEM_BREAK_H */
index 053fba3..7999f4a 100644 (file)
@@ -102,8 +102,7 @@ ps_lgetregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, prgregset_t gregset)
   struct lwp_info *lwp;
   struct thread_info *reg_inferior, *save_inferior;
 
-  lwp = (struct lwp_info *) find_inferior_id (&all_lwps,
-                                             lwpid);
+  lwp = find_lwp_pid (pid_to_ptid (lwpid));
   if (lwp == NULL)
     return PS_ERR;
 
@@ -157,5 +156,5 @@ ps_lsetfpregs (gdb_ps_prochandle_t ph, lwpid_t lwpid, void *fpregset)
 pid_t
 ps_getpid (gdb_ps_prochandle_t ph)
 {
-  return ph->pid;
+  return pid_of (get_thread_lwp (current_inferior));
 }
index c506bf5..103bcc7 100644 (file)
@@ -79,18 +79,11 @@ typedef int socklen_t;
 /* A cache entry for a successfully looked-up symbol.  */
 struct sym_cache
 {
-  const char *name;
+  char *name;
   CORE_ADDR addr;
   struct sym_cache *next;
 };
 
-/* The symbol cache.  */
-static struct sym_cache *symbol_cache;
-
-/* If this flag has been set, assume cache misses are
-   failures.  */
-int all_symbols_looked_up;
-
 int remote_debug = 0;
 struct ui_file *gdb_stdlog;
 
@@ -317,6 +310,29 @@ fromhex (int a)
   return 0;
 }
 
+static const char hexchars[] = "0123456789abcdef";
+
+static int
+ishex (int ch, int *val)
+{
+  if ((ch >= 'a') && (ch <= 'f'))
+    {
+      *val = ch - 'a' + 10;
+      return 1;
+    }
+  if ((ch >= 'A') && (ch <= 'F'))
+    {
+      *val = ch - 'A' + 10;
+      return 1;
+    }
+  if ((ch >= '0') && (ch <= '9'))
+    {
+      *val = ch - '0';
+      return 1;
+    }
+  return 0;
+}
+
 int
 unhexify (char *bin, const char *hex, int count)
 {
@@ -523,6 +539,103 @@ try_rle (char *buf, int remaining, unsigned char *csum, char **p)
   return n + 1;
 }
 
+char *
+unpack_varlen_hex (char *buff, /* packet to parse */
+                  ULONGEST *result)
+{
+  int nibble;
+  ULONGEST retval = 0;
+
+  while (ishex (*buff, &nibble))
+    {
+      buff++;
+      retval = retval << 4;
+      retval |= nibble & 0x0f;
+    }
+  *result = retval;
+  return buff;
+}
+
+/* Write a PTID to BUF.  Returns BUF+CHARACTERS_WRITTEN.  */
+
+char *
+write_ptid (char *buf, ptid_t ptid)
+{
+  int pid, tid;
+
+  if (multi_process)
+    {
+      pid = ptid_get_pid (ptid);
+      if (pid < 0)
+       buf += sprintf (buf, "p-%x.", -pid);
+      else
+       buf += sprintf (buf, "p%x.", pid);
+    }
+  tid = ptid_get_lwp (ptid);
+  if (tid < 0)
+    buf += sprintf (buf, "-%x", -tid);
+  else
+    buf += sprintf (buf, "%x", tid);
+
+  return buf;
+}
+
+ULONGEST
+hex_or_minus_one (char *buf, char **obuf)
+{
+  ULONGEST ret;
+
+  if (strncmp (buf, "-1", 2) == 0)
+    {
+      ret = (ULONGEST) -1;
+      buf += 2;
+    }
+  else
+    buf = unpack_varlen_hex (buf, &ret);
+
+  if (obuf)
+    *obuf = buf;
+
+  return ret;
+}
+
+/* Extract a PTID from BUF.  If non-null, OBUF is set to the to one
+   passed the last parsed char.  Returns null_ptid on error.  */
+ptid_t
+read_ptid (char *buf, char **obuf)
+{
+  char *p = buf;
+  char *pp;
+  ULONGEST pid = 0, tid = 0;
+
+  if (*p == 'p')
+    {
+      /* Multi-process ptid.  */
+      pp = unpack_varlen_hex (p + 1, &pid);
+      if (*pp != '.')
+       error ("invalid remote ptid: %s\n", p);
+
+      p = pp + 1;
+
+      tid = hex_or_minus_one (p, &pp);
+
+      if (obuf)
+       *obuf = pp;
+      return ptid_build (pid, tid, 0);
+    }
+
+  /* No multi-process.  Just a tid.  */
+  tid = hex_or_minus_one (p, &pp);
+
+  /* Since the stub is not sending a process id, then default to
+     what's in the current inferior.  */
+  pid = ptid_get_pid (((struct inferior_list_entry *) current_inferior)->id);
+
+  if (obuf)
+    *obuf = pp;
+  return ptid_build (pid, tid, 0);
+}
+
 /* Send a packet to the remote machine, with error checking.
    The data of the packet is in BUF, and the length of the
    packet is in CNT.  Returns >= 0 on success, -1 otherwise.  */
@@ -957,12 +1070,12 @@ dead_thread_notify (int id)
 }
 
 void
-prepare_resume_reply (char *buf, unsigned long ptid,
+prepare_resume_reply (char *buf, ptid_t ptid,
                      struct target_waitstatus *status)
 {
   if (debug_threads)
-    fprintf (stderr, "Writing resume reply for %lu:%d\n\n",
-            ptid, status->kind);
+    fprintf (stderr, "Writing resume reply for %s:%d\n\n",
+            target_pid_to_str (ptid), status->kind);
 
   switch (status->kind)
     {
@@ -978,7 +1091,7 @@ prepare_resume_reply (char *buf, unsigned long ptid,
 
        saved_inferior = current_inferior;
 
-       current_inferior = gdb_id_to_thread (ptid);
+       current_inferior = find_thread_pid (ptid);
 
        if (the_target->stopped_by_watchpoint != NULL
            && (*the_target->stopped_by_watchpoint) ())
@@ -1021,13 +1134,16 @@ prepare_resume_reply (char *buf, unsigned long ptid,
               in GDB will claim this event belongs to inferior_ptid
               if we do not specify a thread, and there's no way for
               gdbserver to know what inferior_ptid is.  */
-           if (1 || general_thread != ptid)
+           if (1 || !ptid_equal (general_thread, ptid))
              {
                /* In non-stop, don't change the general thread behind
                   GDB's back.  */
                if (!non_stop)
                  general_thread = ptid;
-               sprintf (buf, "thread:%lx;", ptid);
+               sprintf (buf, "thread:");
+               buf += strlen (buf);
+               buf = write_ptid (buf, ptid);
+               strcat (buf, ";");
                buf += strlen (buf);
              }
          }
@@ -1043,10 +1159,18 @@ prepare_resume_reply (char *buf, unsigned long ptid,
       }
       break;
     case TARGET_WAITKIND_EXITED:
-      sprintf (buf, "W%02x", status->value.integer);
+      if (multi_process)
+       sprintf (buf, "W%x;process:%x",
+                status->value.integer, ptid_get_pid (ptid));
+      else
+       sprintf (buf, "W%02x", status->value.integer);
       break;
     case TARGET_WAITKIND_SIGNALLED:
-      sprintf (buf, "X%02x", status->value.sig);
+      if (multi_process)
+       sprintf (buf, "X%x;process:%x",
+                status->value.sig, ptid_get_pid (ptid));
+      else
+       sprintf (buf, "X%02x", status->value.sig);
       break;
     default:
       error ("unhandled waitkind");
@@ -1174,6 +1298,31 @@ decode_search_memory_packet (const char *buf, int packet_len,
   return 0;
 }
 
+static void
+free_sym_cache (struct sym_cache *sym)
+{
+  if (sym != NULL)
+    {
+      free (sym->name);
+      free (sym);
+    }
+}
+
+void
+clear_symbol_cache (struct sym_cache **symcache_p)
+{
+  struct sym_cache *sym, *next;
+
+  /* Check the cache first.  */
+  for (sym = *symcache_p; sym; sym = next)
+    {
+      next = sym->next;
+      free_sym_cache (sym);
+    }
+
+  *symcache_p = NULL;
+}
+
 /* Ask GDB for the address of NAME, and return it in ADDRP if found.
    Returns 1 if the symbol is found, 0 if it is not, -1 on error.  */
 
@@ -1183,9 +1332,12 @@ look_up_one_symbol (const char *name, CORE_ADDR *addrp)
   char own_buf[266], *p, *q;
   int len;
   struct sym_cache *sym;
+  struct process_info *proc;
+
+  proc = current_process ();
 
   /* Check the cache first.  */
-  for (sym = symbol_cache; sym; sym = sym->next)
+  for (sym = proc->symbol_cache; sym; sym = sym->next)
     if (strcmp (name, sym->name) == 0)
       {
        *addrp = sym->addr;
@@ -1197,7 +1349,7 @@ look_up_one_symbol (const char *name, CORE_ADDR *addrp)
      in any libraries loaded after that point, only in symbols in
      libpthread.so.  It might not be an appropriate time to look
      up a symbol, e.g. while we're trying to fetch registers.  */
-  if (all_symbols_looked_up)
+  if (proc->all_symbols_looked_up)
     return 0;
 
   /* Send the request.  */
@@ -1257,8 +1409,8 @@ look_up_one_symbol (const char *name, CORE_ADDR *addrp)
   sym = xmalloc (sizeof (*sym));
   sym->name = xstrdup (name);
   sym->addr = *addrp;
-  sym->next = symbol_cache;
-  symbol_cache = sym;
+  sym->next = proc->symbol_cache;
+  proc->symbol_cache = sym;
 
   return 1;
 }
index 81efecc..998fd0c 100644 (file)
 #include <malloc.h>
 #endif
 
-unsigned long cont_thread;
-unsigned long general_thread;
-unsigned long step_thread;
+ptid_t cont_thread;
+ptid_t general_thread;
+ptid_t step_thread;
 
 int server_waiting;
 
 static int extended_protocol;
-static int attached;
 static int response_needed;
 static int exit_requested;
 
+int multi_process;
 int non_stop;
 
 static char **program_argv, **wrapper_argv;
@@ -90,7 +90,7 @@ int disable_packet_qfThreadInfo;
 
 /* Last status reported to GDB.  */
 static struct target_waitstatus last_status;
-static unsigned long last_ptid;
+static ptid_t last_ptid;
 
 static char *own_buf;
 static unsigned char *mem_buf;
@@ -104,7 +104,7 @@ struct vstop_notif
   struct vstop_notif *next;
 
   /* Thread or process that got the event.  */
-  unsigned long ptid;
+  ptid_t ptid;
 
   /* Event info.  */
   struct target_waitstatus status;
@@ -116,7 +116,7 @@ static struct vstop_notif *notif_queue = NULL;
 /* Put a stop reply to the stop reply queue.  */
 
 static void
-queue_stop_reply (unsigned long ptid, struct target_waitstatus *status)
+queue_stop_reply (ptid_t ptid, struct target_waitstatus *status)
 {
   struct vstop_notif *new_notif;
 
@@ -153,7 +153,7 @@ queue_stop_reply (unsigned long ptid, struct target_waitstatus *status)
    we aren't sending one yet.  */
 
 void
-push_event (unsigned long ptid, struct target_waitstatus *status)
+push_event (ptid_t ptid, struct target_waitstatus *status)
 {
   queue_stop_reply (ptid, status);
 
@@ -170,19 +170,30 @@ push_event (unsigned long ptid, struct target_waitstatus *status)
     }
 }
 
-/* Get rid of the currently pending stop replies.  */
+/* Get rid of the currently pending stop replies for PID.  If PID is
+   -1, then apply to all processes.  */
 
 static void
-discard_queued_stop_replies (void)
+discard_queued_stop_replies (int pid)
 {
-  struct vstop_notif *next;
+  struct vstop_notif *prev = NULL, *reply, *next;
 
-  while (notif_queue)
+  for (reply = notif_queue; reply; reply = next)
     {
-      next = notif_queue->next;
-      notif_queue = next;
+      next = reply->next;
+
+      if (pid == -1
+         || ptid_get_pid (reply->ptid) == pid)
+       {
+         if (reply == notif_queue)
+           notif_queue = next;
+         else
+           prev->next = reply->next;
 
-      free (next);
+         free (reply);
+       }
+      else
+       prev = reply;
     }
 }
 
@@ -209,7 +220,6 @@ static int
 start_inferior (char **argv)
 {
   char **new_argv = argv;
-  attached = 0;
 
   if (wrapper_argv != NULL)
     {
@@ -253,13 +263,13 @@ start_inferior (char **argv)
   if (wrapper_argv != NULL)
     {
       struct thread_resume resume_info;
-      unsigned long ptid;
+      ptid_t ptid;
 
-      resume_info.thread = -1;
+      resume_info.thread = pid_to_ptid (signal_pid);
       resume_info.kind = resume_continue;
       resume_info.sig = 0;
 
-      ptid = mywait (&last_status, 0, 0);
+      ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
 
       if (last_status.kind != TARGET_WAITKIND_STOPPED)
        return signal_pid;
@@ -268,7 +278,7 @@ start_inferior (char **argv)
        {
          (*the_target->resume) (&resume_info, 1);
 
-         mywait (&last_status, 0, 0);
+         mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
          if (last_status.kind != TARGET_WAITKIND_STOPPED)
            return signal_pid;
        }
@@ -279,7 +289,7 @@ start_inferior (char **argv)
 
   /* Wait till we are at 1st instruction in program, return new pid
      (assuming success).  */
-  last_ptid = mywait (&last_status, 0, 0);
+  last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
 
   return signal_pid;
 }
@@ -293,8 +303,6 @@ attach_inferior (int pid)
   if (myattach (pid) != 0)
     return -1;
 
-  attached = 1;
-
   fprintf (stderr, "Attached; pid = %d\n", pid);
   fflush (stderr);
 
@@ -305,7 +313,7 @@ attach_inferior (int pid)
 
   if (!non_stop)
     {
-      last_ptid = mywait (&last_status, 0, 0);
+      last_ptid = mywait (pid_to_ptid (pid), &last_status, 0, 0);
 
       /* GDB knows to ignore the first SIGSTOP after attaching to a running
         process using the "attach" command, but this is different; it's
@@ -656,10 +664,11 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
   /* Reply the current thread id.  */
   if (strcmp ("qC", own_buf) == 0 && !disable_packet_qC)
     {
-      unsigned long gdb_id;
+      ptid_t gdb_id;
       require_running (own_buf);
 
-      if (general_thread != 0 && general_thread != -1)
+      if (!ptid_equal (general_thread, null_ptid)
+         && !ptid_equal (general_thread, minus_one_ptid))
        gdb_id = general_thread;
       else
        {
@@ -667,7 +676,9 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
          gdb_id = thread_to_gdb_id ((struct thread_info *)thread_ptr);
        }
 
-      sprintf (own_buf, "QC%lx", gdb_id);
+      sprintf (own_buf, "QC");
+      own_buf += 2;
+      own_buf = write_ptid (own_buf, gdb_id);
       return;
     }
 
@@ -684,21 +695,28 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
     {
       if (strcmp ("qfThreadInfo", own_buf) == 0)
        {
+         ptid_t gdb_id;
+
          require_running (own_buf);
          thread_ptr = all_threads.head;
-         sprintf (own_buf, "m%x",
-                  thread_to_gdb_id ((struct thread_info *)thread_ptr));
+
+         *own_buf++ = 'm';
+         gdb_id = thread_to_gdb_id ((struct thread_info *)thread_ptr);
+         write_ptid (own_buf, gdb_id);
          thread_ptr = thread_ptr->next;
          return;
        }
 
       if (strcmp ("qsThreadInfo", own_buf) == 0)
        {
+         ptid_t gdb_id;
+
          require_running (own_buf);
          if (thread_ptr != NULL)
            {
-             sprintf (own_buf, "m%x",
-                      thread_to_gdb_id ((struct thread_info *)thread_ptr));
+             *own_buf++ = 'm';
+             gdb_id = thread_to_gdb_id ((struct thread_info *)thread_ptr);
+             write_ptid (own_buf, gdb_id);
              thread_ptr = thread_ptr->next;
              return;
            }
@@ -1046,6 +1064,21 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
   if (strncmp ("qSupported", own_buf, 10) == 0
       && (own_buf[10] == ':' || own_buf[10] == '\0'))
     {
+      char *p = &own_buf[10];
+
+      /* Process each feature being provided by GDB.  The first
+        feature will follow a ':', and latter features will follow
+        ';'.  */
+      if (*p == ':')
+       for (p = strtok (p + 1, ";");
+            p != NULL;
+            p = strtok (NULL, ";"))
+         {
+           /* Record if GDB knows about multiprocess support.  */
+           if (strcmp (p, "multiprocess+") == 0)
+             multi_process = 1;
+         }
+
       sprintf (own_buf, "PacketSize=%x;QPassSignals+", PBUFSIZ - 1);
 
       /* We do not have any hook to indicate whether the target backend
@@ -1073,6 +1106,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
       if (the_target->qxfer_osdata != NULL)
        strcat (own_buf, ";qXfer:osdata:read+");
 
+      strcat (own_buf, ";multiprocess+");
+
       if (target_supports_non_stop ())
        strcat (own_buf, ";QNonStop+");
 
@@ -1086,7 +1121,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
       char *p = own_buf + 12;
       CORE_ADDR parts[2], address = 0;
       int i, err;
-      unsigned long ptid = 0;
+      ptid_t ptid = null_ptid;
 
       require_running (own_buf);
 
@@ -1111,7 +1146,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
            }
 
          if (i == 0)
-           ptid = strtoul (p, NULL, 16);
+           ptid = read_ptid (p, NULL);
          else
            decode_address (&parts[i - 1], p, len);
          p = p2;
@@ -1121,7 +1156,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
        err = 1;
       else
        {
-         struct thread_info *thread = gdb_id_to_thread (ptid);
+         struct thread_info *thread = find_thread_pid (ptid);
 
          if (thread == NULL)
            err = 2;
@@ -1208,10 +1243,30 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
       return;
     }
 
-  if (strcmp (own_buf, "qAttached") == 0)
+  if (strcmp (own_buf, "qAttached") == 0
+      || strncmp (own_buf, "qAttached:", sizeof ("qAttached:") - 1) == 0)
     {
-      require_running (own_buf);
-      strcpy (own_buf, attached ? "1" : "0");
+      struct process_info *process;
+
+      if (own_buf[sizeof ("qAttached") - 1])
+       {
+         int pid = strtoul (own_buf + sizeof ("qAttached:") - 1, NULL, 16);
+         process = (struct process_info *)
+           find_inferior_id (&all_processes, pid_to_ptid (pid));
+       }
+      else
+       {
+         require_running (own_buf);
+         process = current_process ();
+       }
+
+      if (process == NULL)
+       {
+         write_enn (own_buf);
+         return;
+       }
+
+      strcpy (own_buf, process->attached ? "1" : "0");
       return;
     }
 
@@ -1227,7 +1282,7 @@ handle_v_cont (char *own_buf)
   char *p, *q;
   int n = 0, i = 0;
   struct thread_resume *resume_info;
-  struct thread_resume default_action = {0};
+  struct thread_resume default_action = {{0}};
 
   /* Count the number of semicolons in the packet.  There should be one
      for every action.  */
@@ -1277,7 +1332,7 @@ handle_v_cont (char *own_buf)
 
       if (p[0] == 0)
        {
-         resume_info[i].thread = -1;
+         resume_info[i].thread = minus_one_ptid;
          default_action = resume_info[i];
 
          /* Note: we don't increment i here, we'll overwrite this entry
@@ -1285,8 +1340,7 @@ handle_v_cont (char *own_buf)
        }
       else if (p[0] == ':')
        {
-         unsigned int gdb_id = strtoul (p + 1, &q, 16);
-         unsigned long thread_id;
+         ptid_t ptid = read_ptid (p + 1, &q);
 
          if (p == q)
            goto err;
@@ -1294,11 +1348,7 @@ handle_v_cont (char *own_buf)
          if (p[0] != ';' && p[0] != 0)
            goto err;
 
-         thread_id = gdb_id_to_thread_id (gdb_id);
-         if (thread_id)
-           resume_info[i].thread = thread_id;
-         else
-           goto err;
+         resume_info[i].thread = ptid;
 
          i++;
        }
@@ -1309,11 +1359,11 @@ handle_v_cont (char *own_buf)
 
   /* Still used in occasional places in the backend.  */
   if (n == 1
-      && resume_info[0].thread != -1
+      && !ptid_equal (resume_info[0].thread, minus_one_ptid)
       && resume_info[0].kind != resume_stop)
     cont_thread = resume_info[0].thread;
   else
-    cont_thread = -1;
+    cont_thread = minus_one_ptid;
   set_desired_inferior (0);
 
   if (!non_stop)
@@ -1327,7 +1377,7 @@ handle_v_cont (char *own_buf)
     write_ok (own_buf);
   else
     {
-      last_ptid = mywait (&last_status, 0, 1);
+      last_ptid = mywait (minus_one_ptid, &last_status, 0, 1);
       prepare_resume_reply (own_buf, last_ptid, &last_status);
       disable_async_io ();
     }
@@ -1462,6 +1512,30 @@ handle_v_run (char *own_buf)
     }
 }
 
+/* Kill process.  Return 1 if successful, 0 if failure.  */
+int
+handle_v_kill (char *own_buf)
+{
+  int pid;
+  char *p = &own_buf[6];
+
+  pid = strtol (p, NULL, 16);
+  if (pid != 0 && kill_inferior (pid) == 0)
+    {
+      last_status.kind = TARGET_WAITKIND_SIGNALLED;
+      last_status.value.sig = TARGET_SIGNAL_KILL;
+      last_ptid = pid_to_ptid (pid);
+      discard_queued_stop_replies (pid);
+      write_ok (own_buf);
+      return 1;
+    }
+  else
+    {
+      write_enn (own_buf);
+      return 0;
+    }
+}
+
 /* Handle a 'vStopped' packet.  */
 static void
 handle_v_stopped (char *own_buf)
@@ -1473,7 +1547,8 @@ handle_v_stopped (char *own_buf)
       struct vstop_notif *head;
 
       if (remote_debug)
-       fprintf (stderr, "vStopped: acking %ld\n", notif_queue->ptid);
+       fprintf (stderr, "vStopped: acking %s\n",
+                target_pid_to_str (notif_queue->ptid));
 
       head = notif_queue;
       notif_queue = notif_queue->next;
@@ -1510,7 +1585,7 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len)
 
   if (strncmp (own_buf, "vAttach;", 8) == 0)
     {
-      if (target_running ())
+      if (!multi_process && target_running ())
        {
          fprintf (stderr, "Already debugging a process\n");
          write_enn (own_buf);
@@ -1522,7 +1597,7 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len)
 
   if (strncmp (own_buf, "vRun;", 5) == 0)
     {
-      if (target_running ())
+      if (!multi_process && target_running ())
        {
          fprintf (stderr, "Already debugging a process\n");
          write_enn (own_buf);
@@ -1532,6 +1607,18 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len)
       return;
     }
 
+  if (strncmp (own_buf, "vKill;", 6) == 0)
+    {
+      if (!target_running ())
+       {
+         fprintf (stderr, "No process to kill\n");
+         write_enn (own_buf);
+         return;
+       }
+      handle_v_kill (own_buf);
+      return;
+    }
+
   if (strncmp (own_buf, "vStopped", 8) == 0)
     {
       handle_v_stopped (own_buf);
@@ -1556,7 +1643,8 @@ myresume (char *own_buf, int step, int sig)
 
   set_desired_inferior (0);
 
-  valid_cont_thread = (cont_thread != 0 && cont_thread != -1);
+  valid_cont_thread = (!ptid_equal (cont_thread, null_ptid)
+                        && !ptid_equal (cont_thread, minus_one_ptid));
 
   if (step || sig || valid_cont_thread)
     {
@@ -1572,7 +1660,7 @@ myresume (char *own_buf, int step, int sig)
 
   if (!valid_cont_thread)
     {
-      resume_info[n].thread = -1;
+      resume_info[n].thread = minus_one_ptid;
       resume_info[n].kind = resume_continue;
       resume_info[n].sig = 0;
       n++;
@@ -1587,7 +1675,7 @@ myresume (char *own_buf, int step, int sig)
     write_ok (own_buf);
   else
     {
-      last_ptid = mywait (&last_status, 0, 1);
+      last_ptid = mywait (minus_one_ptid, &last_status, 0, 1);
       prepare_resume_reply (own_buf, last_ptid, &last_status);
       disable_async_io ();
     }
@@ -1596,16 +1684,24 @@ myresume (char *own_buf, int step, int sig)
 /* Callback for for_each_inferior.  Make a new stop reply for each
    stopped thread.  */
 
-static void
-queue_stop_reply_callback (struct inferior_list_entry *entry)
+static int
+queue_stop_reply_callback (struct inferior_list_entry *entry, void *arg)
 {
-  struct target_waitstatus status;
+  int pid = * (int *) arg;
 
-  status.kind = TARGET_WAITKIND_STOPPED;
-  status.value.sig = TARGET_SIGNAL_TRAP;
+  if (pid == -1
+      || ptid_get_pid (entry->id) == pid)
+    {
+      struct target_waitstatus status;
+
+      status.kind = TARGET_WAITKIND_STOPPED;
+      status.value.sig = TARGET_SIGNAL_TRAP;
 
-  /* Pass the last stop reply back to GDB, but don't notify.  */
-  queue_stop_reply (entry->id, &status);
+      /* Pass the last stop reply back to GDB, but don't notify.  */
+      queue_stop_reply (entry->id, &status);
+    }
+
+  return 0;
 }
 
 /* Status handler for the '?' packet.  */
@@ -1623,8 +1719,9 @@ handle_status (char *own_buf)
 
   if (non_stop)
     {
-      discard_queued_stop_replies ();
-      for_each_inferior (&all_threads, queue_stop_reply_callback);
+      int pid = -1;
+      discard_queued_stop_replies (pid);
+      find_inferior (&all_threads, queue_stop_reply_callback, &pid);
 
       /* The first is sent immediatly.  OK is sent if there is no
         stopped thread, which is the same handling of the vStopped
@@ -1690,6 +1787,52 @@ gdbserver_show_disableable (FILE *stream)
       break;                                   \
     }
 
+static int
+first_thread_of (struct inferior_list_entry *entry, void *args)
+{
+  int pid = * (int *) args;
+
+  if (ptid_get_pid (entry->id) == pid)
+    return 1;
+
+  return 0;
+}
+
+static void
+kill_inferior_callback (struct inferior_list_entry *entry)
+{
+  struct process_info *process = (struct process_info *) entry;
+  int pid = ptid_get_pid (process->head.id);
+
+  kill_inferior (pid);
+  discard_queued_stop_replies (pid);
+}
+
+static void
+detach_or_kill_inferior_callback (struct inferior_list_entry *entry)
+{
+  struct process_info *process = (struct process_info *) entry;
+  int pid = ptid_get_pid (process->head.id);
+
+  if (process->attached)
+    detach_inferior (pid);
+  else
+    kill_inferior (pid);
+
+  discard_queued_stop_replies (pid);
+}
+
+static void
+join_inferiors_callback (struct inferior_list_entry *entry)
+{
+  struct process_info *process = (struct process_info *) entry;
+
+  /* If we are attached, then we can exit.  Otherwise, we need to hang
+     around doing nothing, until the child is gone.  */
+  if (!process->attached)
+    join_inferior (ptid_get_pid (process->head.id));
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -1827,6 +1970,7 @@ main (int argc, char *argv[])
       exit (1);
     }
 
+  initialize_inferiors ();
   initialize_async_io ();
   initialize_low ();
 
@@ -1861,7 +2005,7 @@ main (int argc, char *argv[])
     {
       last_status.kind = TARGET_WAITKIND_EXITED;
       last_status.value.integer = 0;
-      last_ptid = -1;
+      last_ptid = minus_one_ptid;
     }
 
   /* Don't report shared library events on the initial connection,
@@ -1871,8 +2015,9 @@ main (int argc, char *argv[])
 
   if (setjmp (toplevel))
     {
-      fprintf (stderr, "Killing inferior\n");
-      kill_inferior ();
+      fprintf (stderr, "Killing all inferiors\n");
+      for_each_inferior (&all_processes,
+                        kill_inferior_callback);
       exit (1);
     }
 
@@ -1891,6 +2036,7 @@ main (int argc, char *argv[])
   while (1)
     {
       noack_mode = 0;
+      multi_process = 0;
       non_stop = 0;
 
       remote_open (port);
@@ -1916,10 +2062,8 @@ main (int argc, char *argv[])
 
       if (exit_requested)
        {
-         if (attached)
-           detach_inferior ();
-         else
-           kill_inferior ();
+         for_each_inferior (&all_processes,
+                            detach_or_kill_inferior_callback);
          exit (0);
        }
       else
@@ -1941,6 +2085,7 @@ process_serial_event (void)
   int signal;
   unsigned int len;
   CORE_ADDR mem_addr;
+  int pid;
   unsigned char sig;
   int packet_len;
   int new_packet_len = -1;
@@ -1976,12 +2121,22 @@ process_serial_event (void)
       break;
     case 'D':
       require_running (own_buf);
-      fprintf (stderr, "Detaching from inferior\n");
-      if (detach_inferior () != 0)
+
+      if (multi_process)
+       {
+         i++; /* skip ';' */
+         pid = strtol (&own_buf[i], NULL, 16);
+       }
+      else
+       pid =
+         ptid_get_pid (((struct inferior_list_entry *) current_inferior)->id);
+
+      fprintf (stderr, "Detaching from process %d\n", pid);
+      if (detach_inferior (pid) != 0)
        write_enn (own_buf);
       else
        {
-         discard_queued_stop_replies ();
+         discard_queued_stop_replies (pid);
          write_ok (own_buf);
 
          if (extended_protocol)
@@ -1989,7 +2144,7 @@ process_serial_event (void)
              /* Treat this like a normal program exit.  */
              last_status.kind = TARGET_WAITKIND_EXITED;
              last_status.value.integer = 0;
-             last_ptid = signal_pid;
+             last_ptid = pid_to_ptid (pid);
 
              current_inferior = NULL;
            }
@@ -2001,9 +2156,8 @@ process_serial_event (void)
              /* If we are attached, then we can exit.  Otherwise, we
                 need to hang around doing nothing, until the child is
                 gone.  */
-             if (!attached)
-               join_inferior ();
-
+             for_each_inferior (&all_processes,
+                                join_inferiors_callback);
              exit (0);
            }
        }
@@ -2018,16 +2172,38 @@ process_serial_event (void)
     case 'H':
       if (own_buf[1] == 'c' || own_buf[1] == 'g' || own_buf[1] == 's')
        {
-         unsigned long gdb_id, thread_id;
+         ptid_t gdb_id, thread_id;
+         int pid;
 
          require_running (own_buf);
-         gdb_id = strtoul (&own_buf[2], NULL, 16);
-         if (gdb_id == 0 || gdb_id == -1)
-           thread_id = gdb_id;
+
+         gdb_id = read_ptid (&own_buf[2], NULL);
+
+         pid = ptid_get_pid (gdb_id);
+
+         if (ptid_equal (gdb_id, null_ptid)
+             || ptid_equal (gdb_id, minus_one_ptid))
+           thread_id = null_ptid;
+         else if (pid != 0
+                  && ptid_equal (pid_to_ptid (pid),
+                                 gdb_id))
+           {
+             struct thread_info *thread =
+               (struct thread_info *) find_inferior (&all_threads,
+                                                     first_thread_of,
+                                                     &pid);
+             if (!thread)
+               {
+                 write_enn (own_buf);
+                 break;
+               }
+
+             thread_id = ((struct inferior_list_entry *)thread)->id;
+           }
          else
            {
              thread_id = gdb_id_to_thread_id (gdb_id);
-             if (thread_id == 0)
+             if (ptid_equal (thread_id, null_ptid))
                {
                  write_enn (own_buf);
                  break;
@@ -2036,7 +2212,7 @@ process_serial_event (void)
 
          if (own_buf[1] == 'g')
            {
-             if (thread_id == 0)
+             if (ptid_equal (thread_id, null_ptid))
                {
                  /* GDB is telling us to choose any thread.  Check if
                     the currently selected thread is still valid. If
@@ -2194,13 +2370,12 @@ process_serial_event (void)
     case 'k':
       response_needed = 0;
       if (!target_running ())
-       /* The packet we received doesn't make sense - but we
-          can't reply to it, either.  */
+       /* The packet we received doesn't make sense - but we can't
+          reply to it, either.  */
        return;
 
-      fprintf (stderr, "Killing inferior\n");
-      kill_inferior ();
-      discard_queued_stop_replies ();
+      fprintf (stderr, "Killing all inferiors\n");
+      for_each_inferior (&all_processes, kill_inferior_callback);
 
       /* When using the extended protocol, we wait with no program
         running.  The traditional protocol will exit instead.  */
@@ -2217,12 +2392,13 @@ process_serial_event (void)
        }
     case 'T':
       {
-       unsigned long gdb_id, thread_id;
+       ptid_t gdb_id, thread_id;
 
        require_running (own_buf);
-       gdb_id = strtoul (&own_buf[1], NULL, 16);
+
+       gdb_id = read_ptid (&own_buf[1], NULL);
        thread_id = gdb_id_to_thread_id (gdb_id);
-       if (thread_id == 0)
+       if (ptid_equal (thread_id, null_ptid))
          {
            write_enn (own_buf);
            break;
@@ -2242,10 +2418,8 @@ process_serial_event (void)
       if (extended_protocol)
        {
          if (target_running ())
-           {
-             kill_inferior ();
-             discard_queued_stop_replies ();
-           }
+           for_each_inferior (&all_processes,
+                              kill_inferior_callback);
          fprintf (stderr, "GDBserver restarting\n");
 
          /* Wait till we are at 1st instruction in prog.  */
@@ -2323,7 +2497,8 @@ handle_target_event (int err, gdb_client_data client_data)
   if (debug_threads)
     fprintf (stderr, "handling possible target event\n");
 
-  last_ptid = mywait (&last_status, TARGET_WNOHANG, 1);
+  last_ptid = mywait (minus_one_ptid, &last_status,
+                     TARGET_WNOHANG, 1);
 
   if (last_status.kind != TARGET_WAITKIND_IGNORE)
     {
index 12fef0f..1af5313 100644 (file)
@@ -85,6 +85,70 @@ typedef unsigned char gdb_byte;
    least the size of a (void *).  */
 typedef long long CORE_ADDR;
 
+typedef unsigned long long ULONGEST;
+
+/* The ptid struct is a collection of the various "ids" necessary
+   for identifying the inferior.  This consists of the process id
+   (pid), thread id (tid), and other fields necessary for uniquely
+   identifying the inferior process/thread being debugged.  When
+   manipulating ptids, the constructors, accessors, and predicate
+   declared in server.h should be used.  These are as follows:
+
+      ptid_build       - Make a new ptid from a pid, lwp, and tid.
+      pid_to_ptid      - Make a new ptid from just a pid.
+      ptid_get_pid     - Fetch the pid component of a ptid.
+      ptid_get_lwp     - Fetch the lwp component of a ptid.
+      ptid_get_tid     - Fetch the tid component of a ptid.
+      ptid_equal       - Test to see if two ptids are equal.
+
+   Please do NOT access the struct ptid members directly (except, of
+   course, in the implementation of the above ptid manipulation
+   functions).  */
+
+struct ptid
+  {
+    /* Process id */
+    int pid;
+
+    /* Lightweight process id */
+    long lwp;
+
+    /* Thread id */
+    long tid;
+  };
+
+typedef struct ptid ptid_t;
+
+/* The -1 ptid, often used to indicate either an error condition or a
+   "don't care" condition, i.e, "run all threads".  */
+extern ptid_t minus_one_ptid;
+
+/* The null or zero ptid, often used to indicate no process.  */
+extern ptid_t null_ptid;
+
+/* Attempt to find and return an existing ptid with the given PID,
+   LWP, and TID components.  If none exists, create a new one and
+   return that.  */
+ptid_t ptid_build (int pid, long lwp, long tid);
+
+/* Create a ptid from just a pid.  */
+ptid_t pid_to_ptid (int pid);
+
+/* Fetch the pid (process id) component from a ptid.  */
+int ptid_get_pid (ptid_t ptid);
+
+/* Fetch the lwp (lightweight process) component from a ptid.  */
+long ptid_get_lwp (ptid_t ptid);
+
+/* Fetch the tid (thread id) component from a ptid.  */
+long ptid_get_tid (ptid_t ptid);
+
+/* Compare two ptids to see if they are equal.  */
+extern int ptid_equal (ptid_t p1, ptid_t p2);
+
+/* Return true if this ptid represents a process id.  */
+extern int ptid_is_pid (ptid_t ptid);
+
 /* Generic information for tracking a list of ``inferiors'' - threads,
    processes, etc.  */
 struct inferior_list
@@ -94,7 +158,7 @@ struct inferior_list
 };
 struct inferior_list_entry
 {
-  unsigned long id;
+  ptid_t id;
   struct inferior_list_entry *next;
 };
 
@@ -108,6 +172,36 @@ struct dll_info
   CORE_ADDR base_addr;
 };
 
+struct sym_cache;
+struct breakpoint;
+struct process_info_private;
+
+struct process_info
+{
+  struct inferior_list_entry head;
+
+  int attached;
+
+  /* The symbol cache.  */
+  struct sym_cache *symbol_cache;
+
+  /* If this flag has been set, assume symbol cache misses are
+     failures.  */
+  int all_symbols_looked_up;
+
+  /* The list of memory breakpoints.  */
+  struct breakpoint *breakpoints;
+
+  /* Private target data.  */
+  struct process_info_private *private;
+};
+
+/* Return a pointer to the process that corresponds to the current
+   thread (current_inferior).  It is an error to call this if there is
+   no current thread selected.  */
+
+struct process_info *current_process (void);
+
 #include "regcache.h"
 #include "gdb/signals.h"
 #include "gdb_signals.h"
@@ -120,22 +214,33 @@ void initialize_low ();
 
 /* From inferiors.c.  */
 
+extern struct inferior_list all_processes;
 extern struct inferior_list all_threads;
 extern struct inferior_list all_dlls;
 extern int dlls_changed;
 
+void initialize_inferiors (void);
+
 void add_inferior_to_list (struct inferior_list *list,
                           struct inferior_list_entry *new_inferior);
 void for_each_inferior (struct inferior_list *list,
                        void (*action) (struct inferior_list_entry *));
+
 extern struct thread_info *current_inferior;
 void remove_inferior (struct inferior_list *list,
                      struct inferior_list_entry *entry);
 void remove_thread (struct thread_info *thread);
-void add_thread (unsigned long thread_id, void *target_data, unsigned int);
-unsigned int thread_id_to_gdb_id (unsigned long);
-unsigned int thread_to_gdb_id (struct thread_info *);
-unsigned long gdb_id_to_thread_id (unsigned int);
+void add_thread (ptid_t ptid, void *target_data);
+
+struct process_info *add_process (int pid, int attached);
+void remove_process (struct process_info *process);
+struct process_info *find_process_pid (int pid);
+
+struct thread_info *find_thread_pid (ptid_t ptid);
+
+ptid_t thread_id_to_gdb_id (ptid_t);
+ptid_t thread_to_gdb_id (struct thread_info *);
+ptid_t gdb_id_to_thread_id (ptid_t);
 struct thread_info *gdb_id_to_thread (unsigned int);
 void clear_inferiors (void);
 struct inferior_list_entry *find_inferior
@@ -144,7 +249,7 @@ struct inferior_list_entry *find_inferior
                   void *),
       void *arg);
 struct inferior_list_entry *find_inferior_id (struct inferior_list *list,
-                                             unsigned long id);
+                                             ptid_t id);
 void *inferior_target_data (struct thread_info *);
 void set_inferior_target_data (struct thread_info *, void *);
 void *inferior_regcache_data (struct thread_info *);
@@ -157,9 +262,9 @@ void unloaded_dll (const char *name, CORE_ADDR base_addr);
 
 /* Public variables in server.c */
 
-extern unsigned long cont_thread;
-extern unsigned long general_thread;
-extern unsigned long step_thread;
+extern ptid_t cont_thread;
+extern ptid_t general_thread;
+extern ptid_t step_thread;
 
 extern int server_waiting;
 extern int debug_threads;
@@ -172,6 +277,7 @@ extern int disable_packet_Tthread;
 extern int disable_packet_qC;
 extern int disable_packet_qfThreadInfo;
 
+extern int multi_process;
 extern int non_stop;
 
 /* Functions from event-loop.c.  */
@@ -188,7 +294,7 @@ extern void start_event_loop (void);
 extern void handle_serial_event (int err, gdb_client_data client_data);
 extern void handle_target_event (int err, gdb_client_data client_data);
 
-extern void push_event (unsigned long ptid, struct target_waitstatus *status);
+extern void push_event (ptid_t ptid, struct target_waitstatus *status);
 
 /* Functions from hostio.c.  */
 extern int handle_vFile (char *, int, int *);
@@ -203,6 +309,9 @@ extern int all_symbols_looked_up;
 extern int noack_mode;
 extern int transport_is_reliable;
 
+ptid_t read_ptid (char *buf, char **obuf);
+char *write_ptid (char *buf, ptid_t ptid);
+
 int putpkt (char *buf);
 int putpkt_binary (char *buf, int len);
 int putpkt_notif (char *buf);
@@ -219,7 +328,7 @@ void convert_ascii_to_int (char *from, unsigned char *to, int n);
 void convert_int_to_ascii (unsigned char *from, char *to, int n);
 void new_thread_notify (int id);
 void dead_thread_notify (int id);
-void prepare_resume_reply (char *buf, unsigned long thread_id,
+void prepare_resume_reply (char *buf, ptid_t ptid,
                           struct target_waitstatus *status);
 
 const char *decode_address_to_semicolon (CORE_ADDR *addrp, const char *start);
@@ -244,6 +353,7 @@ int remote_escape_output (const gdb_byte *buffer, int len,
                          gdb_byte *out_buf, int *out_len,
                          int out_maxlen);
 
+void clear_symbol_cache (struct sym_cache **symcache_p);
 int look_up_one_symbol (const char *name, CORE_ADDR *addrp);
 
 void monitor_output (const char *msg);
index ba27beb..eb98410 100644 (file)
@@ -268,6 +268,7 @@ static int
 spu_create_inferior (char *program, char **allargs)
 {
   int pid;
+  ptid_t ptid;
 
   pid = fork ();
   if (pid < 0)
@@ -289,7 +290,10 @@ spu_create_inferior (char *program, char **allargs)
       _exit (0177);
     }
 
-  add_thread (pid, NULL, pid);
+  add_process (pid, 0);
+
+  ptid = ptid_build (pid, pid, 0);
+  add_thread (ptid, NULL);
   return pid;
 }
 
@@ -297,6 +301,8 @@ spu_create_inferior (char *program, char **allargs)
 int
 spu_attach (unsigned long  pid)
 {
+  ptid_t ptid;
+
   if (ptrace (PTRACE_ATTACH, pid, 0, 0) != 0)
     {
       fprintf (stderr, "Cannot attach to process %ld: %s (%d)\n", pid,
@@ -305,27 +311,32 @@ spu_attach (unsigned long  pid)
       _exit (0177);
     }
 
-  add_thread (pid, NULL, pid);
+  add_process (pid, 1);
+  ptid = ptid_build (pid, pid, 0);
+  add_thread (ptid, NULL);
   return 0;
 }
 
 /* Kill the inferior process.  */
-static void
-spu_kill (void)
+static int
+spu_kill (int)
 {
   ptrace (PTRACE_KILL, current_tid, 0, 0);
+  remove_process (pid);
+  return 0;
 }
 
 /* Detach from inferior process.  */
 static int
-spu_detach (void)
+spu_detach (int pid)
 {
   ptrace (PTRACE_DETACH, current_tid, 0, 0);
+  remove_process (pid);
   return 0;
 }
 
 static void
-spu_join (void)
+spu_join (int pid)
 {
   int status, ret;
 
@@ -338,9 +349,9 @@ spu_join (void)
 
 /* Return nonzero if the given thread is still alive.  */
 static int
-spu_thread_alive (unsigned long tid)
+spu_thread_alive (ptid_t ptid)
 {
-  return tid == current_tid;
+  return ptid_get_lwp (ptid) == current_tid;
 }
 
 /* Resume process.  */
@@ -350,8 +361,8 @@ spu_resume (struct thread_resume *resume_info, size_t n)
   size_t i;
 
   for (i = 0; i < n; i++)
-    if (resume_info[i].thread == -1
-       || resume_info[i].thread == current_tid)
+    if (ptid_equal (resume_info[i].thread, minus_one_ptid)
+       || ptid_get_lwp (resume_info[i].thread) == current_tid)
       break;
 
   if (i == n)
@@ -371,8 +382,8 @@ spu_resume (struct thread_resume *resume_info, size_t n)
 }
 
 /* Wait for process, returns status.  */
-static unsigned long
-spu_wait (struct target_waitstatus *ourstatus, int options)
+static ptid_t
+spu_wait (ptid_t ptid, struct target_waitstatus *ourstatus, int options)
 {
   int tid = current_tid;
   int w;
@@ -415,7 +426,8 @@ spu_wait (struct target_waitstatus *ourstatus, int options)
       ourstatus->kind =  TARGET_WAITKIND_EXITED;
       ourstatus->value.integer = WEXITSTATUS (w);
       clear_inferiors ();
-      return ret;
+      remove_process (ret);
+      return pid_to_ptid (ret);
     }
   else if (!WIFSTOPPED (w))
     {
@@ -423,7 +435,8 @@ spu_wait (struct target_waitstatus *ourstatus, int options)
       ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
       ourstatus->value.sig = target_signal_from_host (WTERMSIG (w));
       clear_inferiors ();
-      return ret;
+      remove_process (ret);
+      return pid_to_ptid (ret);
     }
 
   /* After attach, we may have received a SIGSTOP.  Do not return this
@@ -432,12 +445,12 @@ spu_wait (struct target_waitstatus *ourstatus, int options)
     {
       ourstatus->kind = TARGET_WAITKIND_STOPPED;
       ourstatus->value.sig = TARGET_SIGNAL_0;
-      return ret;
+      return ptid_build (ret, ret, 0);
     }
 
   ourstatus->kind = TARGET_WAITKIND_STOPPED;
   ourstatus->value.sig = target_signal_from_host (WSTOPSIG (w));
-  return ret;
+  return ptid_build (ret, ret, 0);
 }
 
 /* Fetch inferior registers.  */
index b570b6c..bbfb5fd 100644 (file)
@@ -29,10 +29,7 @@ set_desired_inferior (int use_general)
   struct thread_info *found;
 
   if (use_general == 1)
-    {
-      found = (struct thread_info *) find_inferior_id (&all_threads,
-                                                      general_thread);
-    }
+    found = find_thread_pid (general_thread);
   else
     {
       found = NULL;
@@ -40,14 +37,14 @@ set_desired_inferior (int use_general)
       /* If we are continuing any (all) thread(s), use step_thread
         to decide which thread to step and/or send the specified
         signal to.  */
-      if ((step_thread != 0 && step_thread != -1)
-         && (cont_thread == 0 || cont_thread == -1))
-       found = (struct thread_info *) find_inferior_id (&all_threads,
-                                                        step_thread);
+      if ((!ptid_equal (step_thread, null_ptid)
+          && !ptid_equal (step_thread, minus_one_ptid))
+         && (ptid_equal (cont_thread, null_ptid)
+             || ptid_equal (cont_thread, minus_one_ptid)))
+       found = find_thread_pid (step_thread);
 
       if (found == NULL)
-       found = (struct thread_info *) find_inferior_id (&all_threads,
-                                                        cont_thread);
+       found = find_thread_pid (cont_thread);
     }
 
   if (found == NULL)
@@ -88,28 +85,24 @@ write_inferior_memory (CORE_ADDR memaddr, const unsigned char *myaddr,
   return res;
 }
 
-unsigned long
-mywait (struct target_waitstatus *ourstatus, int options,
+ptid_t
+mywait (ptid_t ptid, struct target_waitstatus *ourstatus, int options,
        int connected_wait)
 {
-  unsigned long ret;
+  ptid_t ret;
 
   if (connected_wait)
     server_waiting = 1;
 
-  ret = (*the_target->wait) (ourstatus, options);
+  ret = (*the_target->wait) (ptid, ourstatus, options);
 
-  if (ourstatus->kind == TARGET_WAITKIND_EXITED
-      || ourstatus->kind == TARGET_WAITKIND_SIGNALLED)
-    {
-      if (ourstatus->kind == TARGET_WAITKIND_EXITED)
-       fprintf (stderr,
-                "\nChild exited with status %d\n", ourstatus->value.sig);
-      if (ourstatus->kind == TARGET_WAITKIND_SIGNALLED)
-       fprintf (stderr, "\nChild terminated with signal = 0x%x (%s)\n",
-                target_signal_to_host (ourstatus->value.sig),
-                target_signal_to_name (ourstatus->value.sig));
-    }
+  if (ourstatus->kind == TARGET_WAITKIND_EXITED)
+    fprintf (stderr,
+            "\nChild exited with status %d\n", ourstatus->value.sig);
+  else if (ourstatus->kind == TARGET_WAITKIND_SIGNALLED)
+    fprintf (stderr, "\nChild terminated with signal = 0x%x (%s)\n",
+            target_signal_to_host (ourstatus->value.sig),
+            target_signal_to_name (ourstatus->value.sig));
 
   if (connected_wait)
     server_waiting = 0;
@@ -137,3 +130,27 @@ set_target_ops (struct target_ops *target)
   the_target = (struct target_ops *) xmalloc (sizeof (*the_target));
   memcpy (the_target, target, sizeof (*the_target));
 }
+
+/* Convert pid to printable format.  */
+
+const char *
+target_pid_to_str (ptid_t ptid)
+{
+  static char buf[80];
+
+  if (ptid_equal (ptid, minus_one_ptid))
+    snprintf (buf, sizeof (buf), "<all threads>");
+  else if (ptid_equal (ptid, null_ptid))
+    snprintf (buf, sizeof (buf), "<null thread>");
+  else if (ptid_get_tid (ptid) != 0)
+    snprintf (buf, sizeof (buf), "Thread %d.0x%lx",
+             ptid_get_pid (ptid), ptid_get_tid (ptid));
+  else if (ptid_get_lwp (ptid) != 0)
+    snprintf (buf, sizeof (buf), "LWP %d.%ld",
+             ptid_get_pid (ptid), ptid_get_lwp (ptid));
+  else
+    snprintf (buf, sizeof (buf), "Process %d",
+             ptid_get_pid (ptid));
+
+  return buf;
+}
index b7156fd..7ff3849 100644 (file)
@@ -43,7 +43,7 @@ enum resume_kind
 
 struct thread_resume
 {
-  unsigned long thread;
+  ptid_t thread;
 
   /* How to "resume".  */
   enum resume_kind kind;
@@ -96,7 +96,7 @@ struct target_waitstatus
       {
        int integer;
        enum target_signal sig;
-       unsigned long related_pid;
+       ptid_t related_pid;
        char *execd_pathname;
       }
     value;
@@ -129,31 +129,38 @@ struct target_ops
 
   int (*attach) (unsigned long pid);
 
-  /* Kill all inferiors.  */
+  /* Kill inferior PID.  Return -1 on failure, and 0 on success.  */
 
-  void (*kill) (void);
+  int (*kill) (int pid);
 
-  /* Detach from all inferiors.
-     Return -1 on failure, and 0 on success.  */
+  /* Detach from inferior PID. Return -1 on failure, and 0 on
+     success.  */
 
-  int (*detach) (void);
+  int (*detach) (int pid);
 
-  /* Wait for inferiors to end.  */
-
-  void (*join) (void);
+  /* Wait for inferior PID to exit.  */
+  void (*join) (int pid);
 
   /* Return 1 iff the thread with process ID PID is alive.  */
 
-  int (*thread_alive) (unsigned long pid);
+  int (*thread_alive) (ptid_t pid);
 
   /* Resume the inferior process.  */
 
   void (*resume) (struct thread_resume *resume_info, size_t n);
 
   /* Wait for the inferior process or thread to change state.  Store
-     status through argument pointer STATUS.  */
+     status through argument pointer STATUS.
+
+     PTID = -1 to wait for any pid to do something, PTID(pid,0,0) to
+     wait for any thread of process pid to do something.  Return ptid
+     of child, or -1 in case of error; store status through argument
+     pointer STATUS.  OPTIONS is a bit set of options defined as
+     TARGET_W* above.  If options contains TARGET_WNOHANG and there's
+     no child stop to report, return is
+     null_ptid/TARGET_WAITKIND_IGNORE.  */
 
-  unsigned long (*wait) (struct target_waitstatus *status, int options);
+  ptid_t (*wait) (ptid_t ptid, struct target_waitstatus *status, int options);
 
   /* Fetch registers from the inferior process.
 
@@ -280,11 +287,11 @@ void set_target_ops (struct target_ops *);
 #define myattach(pid) \
   (*the_target->attach) (pid)
 
-#define kill_inferior() \
-  (*the_target->kill) ()
+#define kill_inferior(pid) \
+  (*the_target->kill) (pid)
 
-#define detach_inferior() \
-  (*the_target->detach) ()
+#define detach_inferior(pid) \
+  (*the_target->detach) (pid)
 
 #define mythread_alive(pid) \
   (*the_target->thread_alive) (pid)
@@ -295,8 +302,8 @@ void set_target_ops (struct target_ops *);
 #define store_inferior_registers(regno) \
   (*the_target->store_registers) (regno)
 
-#define join_inferior() \
-  (*the_target->join) ()
+#define join_inferior(pid) \
+  (*the_target->join) (pid)
 
 #define target_supports_non_stop() \
   (the_target->supports_non_stop ? (*the_target->supports_non_stop ) () : 0)
@@ -308,8 +315,8 @@ void set_target_ops (struct target_ops *);
 
 int start_non_stop (int nonstop);
 
-unsigned long mywait (struct target_waitstatus *ourstatus, int options,
-                     int connected_wait);
+ptid_t mywait (ptid_t ptid, struct target_waitstatus *ourstatus, int options,
+              int connected_wait);
 
 int read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len);
 
@@ -318,4 +325,6 @@ int write_inferior_memory (CORE_ADDR memaddr, const unsigned char *myaddr,
 
 void set_desired_inferior (int id);
 
+const char *target_pid_to_str (ptid_t);
+
 #endif /* TARGET_H */
index adafb2c..936bb0f 100644 (file)
@@ -35,14 +35,7 @@ static int thread_db_use_events;
 
 #include <stdint.h>
 
-/* Structure that identifies the child process for the
-   <proc_service.h> interface.  */
-static struct ps_prochandle proc_handle;
-
-/* Connection to the libthread_db library.  */
-static td_thragent_t *thread_agent;
-
-static int find_one_thread (int);
+static int find_one_thread (ptid_t);
 static int find_new_threads_callback (const td_thrhandle_t *th_p, void *data);
 
 static const char *
@@ -137,6 +130,7 @@ thread_db_create_event (CORE_ADDR where)
   td_event_msg_t msg;
   td_err_e err;
   struct lwp_info *lwp;
+  struct process_info_private *proc = current_process()->private;
 
   if (debug_threads)
     fprintf (stderr, "Thread creation event.\n");
@@ -145,7 +139,7 @@ thread_db_create_event (CORE_ADDR where)
      In the LinuxThreads implementation, this is safe,
      because all events come from the manager thread
      (except for its own creation, of course).  */
-  err = td_ta_event_getmsg (thread_agent, &msg);
+  err = td_ta_event_getmsg (proc->thread_agent, &msg);
   if (err != TD_OK)
     fprintf (stderr, "thread getmsg err: %s\n",
             thread_db_err_str (err));
@@ -155,7 +149,7 @@ thread_db_create_event (CORE_ADDR where)
      created threads.  */
   lwp = get_thread_lwp (current_inferior);
   if (lwp->thread_known == 0)
-    find_one_thread (lwpid_of (lwp));
+    find_one_thread (lwp->head.id);
 
   /* msg.event == TD_EVENT_CREATE */
 
@@ -181,6 +175,7 @@ thread_db_enable_reporting ()
   td_thr_events_t events;
   td_notify_t notify;
   td_err_e err;
+  struct process_info_private *proc = current_process()->private;
 
   /* Set the process wide mask saying which events we're interested in.  */
   td_event_emptyset (&events);
@@ -192,7 +187,7 @@ thread_db_enable_reporting ()
   td_event_addset (&events, TD_DEATH);
 #endif
 
-  err = td_ta_set_event (thread_agent, &events);
+  err = td_ta_set_event (proc->thread_agent, &events);
   if (err != TD_OK)
     {
       warning ("Unable to set global thread event mask: %s",
@@ -201,7 +196,7 @@ thread_db_enable_reporting ()
     }
 
   /* Get address for thread creation breakpoint.  */
-  err = td_ta_event_addr (thread_agent, TD_CREATE, &notify);
+  err = td_ta_event_addr (proc->thread_agent, TD_CREATE, &notify);
   if (err != TD_OK)
     {
       warning ("Unable to get location for thread creation breakpoint: %s",
@@ -216,7 +211,7 @@ thread_db_enable_reporting ()
      with actual thread deaths (via wait).  */
 
   /* Get address for thread death breakpoint.  */
-  err = td_ta_event_addr (thread_agent, TD_DEATH, &notify);
+  err = td_ta_event_addr (proc->thread_agent, TD_DEATH, &notify);
   if (err != TD_OK)
     {
       warning ("Unable to get location for thread death breakpoint: %s",
@@ -231,21 +226,23 @@ thread_db_enable_reporting ()
 }
 
 static int
-find_one_thread (int lwpid)
+find_one_thread (ptid_t ptid)
 {
   td_thrhandle_t th;
   td_thrinfo_t ti;
   td_err_e err;
   struct thread_info *inferior;
   struct lwp_info *lwp;
+  struct process_info_private *proc = current_process()->private;
+  int lwpid = ptid_get_lwp (ptid);
 
-  inferior = (struct thread_info *) find_inferior_id (&all_threads, lwpid);
+  inferior = (struct thread_info *) find_inferior_id (&all_threads, ptid);
   lwp = get_thread_lwp (inferior);
   if (lwp->thread_known)
     return 1;
 
   /* Get information about this thread.  */
-  err = td_ta_map_lwp2thr (thread_agent, lwpid_of (lwp), &th);
+  err = td_ta_map_lwp2thr (proc->thread_agent, lwpid, &th);
   if (err != TD_OK)
     error ("Cannot get thread handle for LWP %d: %s",
           lwpid, thread_db_err_str (err));
@@ -259,10 +256,10 @@ find_one_thread (int lwpid)
     fprintf (stderr, "Found thread %ld (LWP %d)\n",
             ti.ti_tid, ti.ti_lid);
 
-  if (lwpid_of (lwp) != ti.ti_lid)
+  if (lwpid != ti.ti_lid)
     {
       warning ("PID mismatch!  Expected %ld, got %ld",
-              (long) lwpid_of (lwp), (long) ti.ti_lid);
+              (long) lwpid, (long) ti.ti_lid);
       return 0;
     }
 
@@ -289,29 +286,24 @@ static void
 maybe_attach_thread (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p)
 {
   td_err_e err;
-  struct thread_info *inferior;
   struct lwp_info *lwp;
 
-  inferior = (struct thread_info *) find_inferior_id (&all_threads,
-                                                     ti_p->ti_lid);
-  if (inferior != NULL)
+  lwp = find_lwp_pid (pid_to_ptid (ti_p->ti_lid));
+  if (lwp != NULL)
     return;
 
   if (debug_threads)
     fprintf (stderr, "Attaching to thread %ld (LWP %d)\n",
             ti_p->ti_tid, ti_p->ti_lid);
   linux_attach_lwp (ti_p->ti_lid);
-  inferior = (struct thread_info *) find_inferior_id (&all_threads,
-                                                     ti_p->ti_lid);
-  if (inferior == NULL)
+  lwp = find_lwp_pid (pid_to_ptid (ti_p->ti_lid));
+  if (lwp == NULL)
     {
       warning ("Could not attach to thread %ld (LWP %d)\n",
               ti_p->ti_tid, ti_p->ti_lid);
       return;
     }
 
-  lwp = inferior_target_data (inferior);
-
   lwp->thread_known = 1;
   lwp->th = *th_p;
 
@@ -347,15 +339,18 @@ static void
 thread_db_find_new_threads (void)
 {
   td_err_e err;
+  ptid_t ptid = ((struct inferior_list_entry *) current_inferior)->id;
+  struct process_info_private *proc = current_process()->private;
 
   /* This function is only called when we first initialize thread_db.
      First locate the initial thread.  If it is not ready for
      debugging yet, then stop.  */
-  if (find_one_thread (all_threads.head->id) == 0)
+  if (find_one_thread (ptid) == 0)
     return;
 
   /* Iterate over all user-space threads to discover new threads.  */
-  err = td_ta_thr_iter (thread_agent, find_new_threads_callback, NULL,
+  err = td_ta_thr_iter (proc->thread_agent,
+                       find_new_threads_callback, NULL,
                        TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
                        TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
   if (err != TD_OK)
@@ -385,18 +380,22 @@ thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset,
   psaddr_t addr;
   td_err_e err;
   struct lwp_info *lwp;
+  struct thread_info *saved_inferior;
 
   lwp = get_thread_lwp (thread);
   if (!lwp->thread_known)
-    find_one_thread (lwpid_of (lwp));
+    find_one_thread (lwp->head.id);
   if (!lwp->thread_known)
     return TD_NOTHR;
 
+  saved_inferior = current_inferior;
+  current_inferior = thread;
   /* Note the cast through uintptr_t: this interface only works if
      a target address fits in a psaddr_t, which is a host pointer.
      So a 32-bit debugger can not access 64-bit TLS through this.  */
   err = td_thr_tls_get_addr (&lwp->th, (psaddr_t) (uintptr_t) load_module,
                             offset, &addr);
+  current_inferior = saved_inferior;
   if (err == TD_OK)
     {
       *address = (CORE_ADDR) (uintptr_t) addr;
@@ -413,6 +412,8 @@ int
 thread_db_init (int use_events)
 {
   int err;
+  struct process_info *proc = current_process ();
+  struct process_info_private *priv = proc->private;
 
   /* FIXME drow/2004-10-16: This is the "overall process ID", which
      GNU/Linux calls tgid, "thread group ID".  When we support
@@ -424,14 +425,10 @@ thread_db_init (int use_events)
 
      This isn't the only place in gdbserver that assumes that the first
      process in the list is the thread group leader.  */
-  proc_handle.pid = ((struct inferior_list_entry *)current_inferior)->id;
-
-  /* Allow new symbol lookups.  */
-  all_symbols_looked_up = 0;
 
   thread_db_use_events = use_events;
 
-  err = td_ta_new (&proc_handle, &thread_agent);
+  err = td_ta_new (&priv->proc_handle, &priv->thread_agent);
   switch (err)
     {
     case TD_NOLIBTHREAD:
@@ -445,7 +442,7 @@ thread_db_init (int use_events)
        return 0;
       thread_db_find_new_threads ();
       thread_db_look_up_symbols ();
-      all_symbols_looked_up = 1;
+      proc->all_symbols_looked_up = 1;
       return 1;
 
     default:
index 1d7c203..f3943ab 100644 (file)
@@ -94,11 +94,17 @@ static void win32_resume (struct thread_resume *resume_info, size_t n);
 
 /* Get the thread ID from the current selected inferior (the current
    thread).  */
-static DWORD
-current_inferior_tid (void)
+static ptid_t
+current_inferior_ptid (void)
 {
-  win32_thread_info *th = inferior_target_data (current_inferior);
-  return th->tid;
+  return ((struct inferior_list_entry*) current_inferior)->id;
+}
+
+/* The current debug event from WaitForDebugEvent.  */
+static ptid_t
+debug_event_ptid (DEBUG_EVENT *event)
+{
+  return ptid_build (event->dwProcessId, event->dwThreadId, 0);
 }
 
 /* Get the thread context of the thread associated with TH.  */
@@ -137,12 +143,12 @@ win32_set_thread_context (win32_thread_info *th)
 /* Find a thread record given a thread id.  If GET_CONTEXT is set then
    also retrieve the context for this thread.  */
 static win32_thread_info *
-thread_rec (DWORD id, int get_context)
+thread_rec (ptid_t ptid, int get_context)
 {
   struct thread_info *thread;
   win32_thread_info *th;
 
-  thread = (struct thread_info *) find_inferior_id (&all_threads, id);
+  thread = (struct thread_info *) find_inferior_id (&all_threads, ptid);
   if (thread == NULL)
     return NULL;
 
@@ -169,20 +175,21 @@ thread_rec (DWORD id, int get_context)
 
 /* Add a thread to the thread list.  */
 static win32_thread_info *
-child_add_thread (DWORD tid, HANDLE h)
+child_add_thread (DWORD pid, DWORD tid, HANDLE h)
 {
   win32_thread_info *th;
+  ptid_t ptid = ptid_build (pid, tid, 0);
 
-  if ((th = thread_rec (tid, FALSE)))
+  if ((th = thread_rec (ptid, FALSE)))
     return th;
 
   th = xcalloc (1, sizeof (*th));
   th->tid = tid;
   th->h = h;
 
-  add_thread (tid, th, (unsigned int) tid);
+  add_thread (ptid, th);
   set_inferior_regcache_data ((struct thread_info *)
-                             find_inferior_id (&all_threads, tid),
+                             find_inferior_id (&all_threads, ptid),
                              new_register_cache ());
 
   if (the_low_target.thread_added != NULL)
@@ -204,15 +211,17 @@ delete_thread_info (struct inferior_list_entry *thread)
 
 /* Delete a thread from the list of threads.  */
 static void
-child_delete_thread (DWORD id)
+child_delete_thread (DWORD pid, DWORD tid)
 {
   struct inferior_list_entry *thread;
+  ptid_t ptid;
 
   /* If the last thread is exiting, just return.  */
   if (all_threads.head == all_threads.tail)
     return;
 
-  thread = find_inferior_id (&all_threads, id);
+  ptid = ptid_build (pid, tid, 0);
+  thread = find_inferior_id (&all_threads, ptid);
   if (thread == NULL)
     return;
 
@@ -250,7 +259,7 @@ child_init_thread_list (void)
 }
 
 static void
-do_initial_child_stuff (HANDLE proch, DWORD pid)
+do_initial_child_stuff (HANDLE proch, DWORD pid, int attached)
 {
   last_sig = TARGET_SIGNAL_0;
 
@@ -263,6 +272,7 @@ do_initial_child_stuff (HANDLE proch, DWORD pid)
 
   memset (&current_event, 0, sizeof (current_event));
 
+  add_process (pid, attached);
   child_init_thread_list ();
 
   if (the_low_target.initial_stuff != NULL)
@@ -320,7 +330,7 @@ static void
 child_fetch_inferior_registers (int r)
 {
   int regno;
-  win32_thread_info *th = thread_rec (current_inferior_tid (), TRUE);
+  win32_thread_info *th = thread_rec (current_inferior_ptid (), TRUE);
   if (r == -1 || r == 0 || r > NUM_REGS)
     child_fetch_inferior_registers (NUM_REGS);
   else
@@ -334,7 +344,7 @@ static void
 child_store_inferior_registers (int r)
 {
   int regno;
-  win32_thread_info *th = thread_rec (current_inferior_tid (), TRUE);
+  win32_thread_info *th = thread_rec (current_inferior_ptid (), TRUE);
   if (r == -1 || r == 0 || r > NUM_REGS)
     child_store_inferior_registers (NUM_REGS);
   else
@@ -540,7 +550,7 @@ win32_create_inferior (char *program, char **program_args)
   CloseHandle (pi.hThread);
 #endif
 
-  do_initial_child_stuff (pi.hProcess, pi.dwProcessId);
+  do_initial_child_stuff (pi.hProcess, pi.dwProcessId, 0);
 
   return current_process_id;
 }
@@ -571,7 +581,7 @@ win32_attach (unsigned long pid)
 
          /* win32_wait needs to know we're attaching.  */
          attaching = 1;
-         do_initial_child_stuff (h, pid);
+         do_initial_child_stuff (h, pid, 1);
          return 0;
        }
 
@@ -639,11 +649,13 @@ win32_clear_inferiors (void)
 }
 
 /* Kill all inferiors.  */
-static void
-win32_kill (void)
+static int
+win32_kill (int pid)
 {
+  struct process_info *process;
+
   if (current_process_handle == NULL)
-    return;
+    return -1;
 
   TerminateProcess (current_process_handle, 0);
   for (;;)
@@ -662,12 +674,17 @@ win32_kill (void)
     }
 
   win32_clear_inferiors ();
+
+  process = find_process_pid (pid);
+  remove_process (process);
+  return 0;
 }
 
-/* Detach from all inferiors.  */
+/* Detach from inferior PID.  */
 static int
-win32_detach (void)
+win32_detach (int pid)
 {
+  struct process_info *process;
   winapi_DebugActiveProcessStop DebugActiveProcessStop = NULL;
   winapi_DebugSetProcessKillOnExit DebugSetProcessKillOnExit = NULL;
 #ifdef _WIN32_WCE
@@ -684,7 +701,7 @@ win32_detach (void)
 
   {
     struct thread_resume resume;
-    resume.thread = -1;
+    resume.thread = minus_one_ptid;
     resume.kind = resume_continue;
     resume.sig = 0;
     win32_resume (&resume, 1);
@@ -694,6 +711,8 @@ win32_detach (void)
     return -1;
 
   DebugSetProcessKillOnExit (FALSE);
+  process = find_process_pid (pid);
+  remove_process (process);
 
   win32_clear_inferiors ();
   return 0;
@@ -701,11 +720,9 @@ win32_detach (void)
 
 /* Wait for inferiors to end.  */
 static void
-win32_join (void)
+win32_join (int pid)
 {
-  extern unsigned long signal_pid;
-
-  HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, signal_pid);
+  HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
   if (h != NULL)
     {
       WaitForSingleObject (h, INFINITE);
@@ -715,13 +732,13 @@ win32_join (void)
 
 /* Return 1 iff the thread with thread ID TID is alive.  */
 static int
-win32_thread_alive (unsigned long tid)
+win32_thread_alive (ptid_t ptid)
 {
   int res;
 
   /* Our thread list is reliable; don't bother to poll target
      threads.  */
-  if (find_inferior_id (&all_threads, tid) != NULL)
+  if (find_inferior_id (&all_threads, ptid) != NULL)
     res = 1;
   else
     res = 0;
@@ -738,11 +755,12 @@ win32_resume (struct thread_resume *resume_info, size_t n)
   int step;
   win32_thread_info *th;
   DWORD continue_status = DBG_CONTINUE;
+  ptid_t ptid;
 
   /* This handles the very limited set of resume packets that GDB can
      currently produce.  */
 
-  if (n == 1 && resume_info[0].thread == -1)
+  if (n == 1 && ptid_equal (resume_info[0].thread, minus_one_ptid))
     tid = -1;
   else if (n > 1)
     tid = -1;
@@ -751,7 +769,7 @@ win32_resume (struct thread_resume *resume_info, size_t n)
        the Windows resume code do the right thing for thread switching.  */
     tid = current_event.dwThreadId;
 
-  if (resume_info[0].thread != -1)
+  if (!ptid_equal (resume_info[0].thread, minus_one_ptid))
     {
       sig = resume_info[0].sig;
       step = resume_info[0].kind == resume_step;
@@ -777,7 +795,8 @@ win32_resume (struct thread_resume *resume_info, size_t n)
   last_sig = TARGET_SIGNAL_0;
 
   /* Get context for the currently selected thread.  */
-  th = thread_rec (current_event.dwThreadId, FALSE);
+  ptid = debug_event_ptid (&current_event);
+  th = thread_rec (ptid, FALSE);
   if (th)
     {
       if (th->context.ContextFlags)
@@ -1295,6 +1314,8 @@ auto_delete_breakpoint (CORE_ADDR stop_pc)
 static int
 get_child_debug_event (struct target_waitstatus *ourstatus)
 {
+  ptid_t ptid;
+
   last_sig = TARGET_SIGNAL_0;
   ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
 
@@ -1349,9 +1370,9 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
 
  gotevent:
 
+  ptid = debug_event_ptid (&current_event);
   current_inferior =
-    (struct thread_info *) find_inferior_id (&all_threads,
-                                            current_event.dwThreadId);
+    (struct thread_info *) find_inferior_id (&all_threads, ptid);
 
   switch (current_event.dwDebugEventCode)
     {
@@ -1362,8 +1383,9 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
                (unsigned) current_event.dwThreadId));
 
       /* Record the existence of this thread.  */
-      child_add_thread (current_event.dwThreadId,
-                            current_event.u.CreateThread.hThread);
+      child_add_thread (current_event.dwProcessId,
+                       current_event.dwThreadId,
+                       current_event.u.CreateThread.hThread);
       break;
 
     case EXIT_THREAD_DEBUG_EVENT:
@@ -1371,7 +1393,8 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
                "for pid=%d tid=%x\n",
                (unsigned) current_event.dwProcessId,
                (unsigned) current_event.dwThreadId));
-      child_delete_thread (current_event.dwThreadId);
+      child_delete_thread (current_event.dwProcessId,
+                          current_event.dwThreadId);
       break;
 
     case CREATE_PROCESS_DEBUG_EVENT:
@@ -1388,10 +1411,11 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
       ourstatus->value.execd_pathname = "Main executable";
 
       /* Add the main thread.  */
-      child_add_thread (main_thread_id,
+      child_add_thread (current_event.dwProcessId,
+                       main_thread_id,
                        current_event.u.CreateProcessInfo.hThread);
 
-      ourstatus->value.related_pid = current_event.dwThreadId;
+      ourstatus->value.related_pid = debug_event_ptid (&current_event);
 #ifdef _WIN32_WCE
       if (!attaching)
        {
@@ -1467,17 +1491,18 @@ get_child_debug_event (struct target_waitstatus *ourstatus)
     }
 
   current_inferior =
-    (struct thread_info *) find_inferior_id (&all_threads,
-                                            current_event.dwThreadId);
+    (struct thread_info *) find_inferior_id (&all_threads, ptid);
   return 1;
 }
 
 /* Wait for the inferior process to change state.
    STATUS will be filled in with a response code to send to GDB.
    Returns the signal which caused the process to stop. */
-static unsigned long
-win32_wait (struct target_waitstatus *ourstatus, int options)
+static ptid_t
+win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus, int options)
 {
+  struct process_info *process;
+
   while (1)
     {
       if (!get_child_debug_event (ourstatus))
@@ -1489,8 +1514,10 @@ win32_wait (struct target_waitstatus *ourstatus, int options)
          OUTMSG2 (("Child exited with retcode = %x\n",
                    ourstatus->value.integer));
 
+         process = find_process_pid (current_process_id);
+         remove_process (process);
          win32_clear_inferiors ();
-         return current_event.dwProcessId;
+         return pid_to_ptid (current_event.dwProcessId);
        case TARGET_WAITKIND_STOPPED:
        case TARGET_WAITKIND_LOADED:
          OUTMSG2 (("Child Stopped with signal = %d \n",
@@ -1512,7 +1539,7 @@ win32_wait (struct target_waitstatus *ourstatus, int options)
          if (ourstatus->kind == TARGET_WAITKIND_LOADED)
            ourstatus->kind = TARGET_WAITKIND_STOPPED;
 
-         return current_event.dwThreadId;
+         return debug_event_ptid (&current_event);
        default:
          OUTMSG (("Ignoring unknown internal event, %d\n", ourstatus->kind));
          /* fall-through */