unsigned char mywait (char *status) { int pid; union wait w; enable_async_io (); pid = waitpid (inferior_pid, &w, 0); disable_async_io (); if (pid != inferior_pid) perror_with_name ("wait"); if (WIFEXITED (w)) { fprintf (stderr, "\nChild exited with retcode = %x \n", WEXITSTATUS (w)); *status = 'W'; return ((unsigned char) WEXITSTATUS (w)); } else if (!WIFSTOPPED (w)) { fprintf (stderr, "\nChild terminated with signal = %x \n", WTERMSIG (w)); *status = 'X'; return ((unsigned char) WTERMSIG (w)); } fetch_inferior_registers (0); *status = 'T'; return ((unsigned char) WSTOPSIG (w)); }
static void fbsd_resume (struct thread_resume *resume_info) { int pending_flag; /* Yes, the use of a global here is rather ugly. */ resume_ptr = resume_info; for_each_inferior (&all_threads, fbsd_set_resume_request); /* If there is a thread which would otherwise be resumed, which has a pending status, then don't resume any threads - we can just report the pending status. Make sure to queue any signals that would otherwise be sent. */ pending_flag = 0; find_inferior (&all_processes, resume_status_pending_p, &pending_flag); if (debug_threads) { if (pending_flag) fprintf (stderr, "Not resuming, pending status\n"); else fprintf (stderr, "Resuming, no pending status\n"); } if (pending_flag) for_each_inferior (&all_threads, fbsd_queue_one_thread); else { block_async_io (); enable_async_io (); for_each_inferior (&all_threads, fbsd_continue_one_thread); } }
void myresume (char *own_buf, int step, int *signalp, char *statusp) { struct thread_resume resume_info[2]; int n = 0; int sig = *signalp; set_desired_inferior (0); if (step || sig || (cont_thread != 0 && cont_thread != -1)) { resume_info[0].thread = ((struct inferior_list_entry *) current_inferior)->id; resume_info[0].step = step; resume_info[0].sig = sig; resume_info[0].leave_stopped = 0; n++; } resume_info[n].thread = -1; resume_info[n].step = 0; resume_info[n].sig = 0; resume_info[n].leave_stopped = (cont_thread != 0 && cont_thread != -1); enable_async_io (); (*the_target->resume) (resume_info); *signalp = mywait (statusp, 1); prepare_resume_reply (own_buf, *statusp, *signalp); disable_async_io (); }
static unsigned char fbsd_wait (char *status) { int w; struct thread_info *child = NULL; retry: /* If we were only supposed to resume one thread, only wait for that thread - if it's still alive. If it died, however - which can happen if we're coming from the thread death case below - 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 (cont_thread > 0) { child = (struct thread_info *) find_inferior_id (&all_threads, cont_thread); /* No stepping, no signal - unless one is pending already, of course. */ if (child == NULL) { struct thread_resume resume_info; resume_info.thread = -1; resume_info.step = resume_info.sig = resume_info.leave_stopped = 0; fbsd_resume (&resume_info); } } enable_async_io (); unblock_async_io (); w = fbsd_wait_for_event (child); stop_all_processes (); disable_async_io (); /* If we are waiting for a particular child, and it exited, fbsd_wait_for_event will return its exit status. Similarly if the last child exited. If this is not the last child, however, do not report it as exited until there is a 'thread exited' response available in the remote protocol. Instead, just wait for another event. This should be safe, because if the thread crashed we will already have reported the termination signal to GDB; that should stop any in-progress stepping operations, etc. Report the exit status of the last thread to exit. This matches LinuxThreads' behavior. */ if (all_threads.head == all_threads.tail) { if (WIFEXITED (w)) { fprintf (stderr, "\nChild exited with retcode = %x \n", WEXITSTATUS (w)); *status = 'W'; clear_inferiors (); free (all_processes.head); all_processes.head = all_processes.tail = NULL; return ((unsigned char) WEXITSTATUS (w)); } else if (!WIFSTOPPED (w)) { fprintf (stderr, "\nChild terminated with signal = %x \n", WTERMSIG (w)); *status = 'X'; clear_inferiors (); free (all_processes.head); all_processes.head = all_processes.tail = NULL; return ((unsigned char) WTERMSIG (w)); } } else { if (!WIFSTOPPED (w)) goto retry; } *status = 'T'; return ((unsigned char) WSTOPSIG (w)); }
/* Parse vCont packets. */ void handle_v_cont (char *own_buf, char *status, int *signal) { char *p, *q; int n = 0, i = 0; struct thread_resume *resume_info, default_action; /* Count the number of semicolons in the packet. There should be one for every action. */ p = &own_buf[5]; while (p) { n++; p++; p = strchr (p, ';'); } /* Allocate room for one extra action, for the default remain-stopped behavior; if no default action is in the list, we'll need the extra slot. */ resume_info = malloc ((n + 1) * sizeof (resume_info[0])); default_action.thread = -1; default_action.leave_stopped = 1; default_action.step = 0; default_action.sig = 0; p = &own_buf[5]; i = 0; while (*p) { p++; resume_info[i].leave_stopped = 0; if (p[0] == 's' || p[0] == 'S') resume_info[i].step = 1; else if (p[0] == 'c' || p[0] == 'C') resume_info[i].step = 0; else goto err; if (p[0] == 'S' || p[0] == 'C') { int sig; sig = strtol (p + 1, &q, 16); if (p == q) goto err; p = q; if (!target_signal_to_host_p (sig)) goto err; resume_info[i].sig = target_signal_to_host (sig); } else { resume_info[i].sig = 0; p = p + 1; } if (p[0] == 0) { resume_info[i].thread = -1; default_action = resume_info[i]; /* Note: we don't increment i here, we'll overwrite this entry the next time through. */ } else if (p[0] == ':') { unsigned int gdb_id = strtoul (p + 1, &q, 16); unsigned long thread_id; if (p == q) goto err; p = q; 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; i++; } } resume_info[i] = default_action; /* Still used in occasional places in the backend. */ if (n == 1 && resume_info[0].thread != -1) cont_thread = resume_info[0].thread; else cont_thread = -1; set_desired_inferior (0); enable_async_io (); (*the_target->resume) (resume_info); free (resume_info); *signal = mywait (status, 1); prepare_resume_reply (own_buf, *status, *signal); disable_async_io (); return; err: write_enn (own_buf); free (resume_info); return; }