blob: b2ca2bb6ce9689cfd3ec9bb07b0dd95b0de7df60 [file] [log] [blame]
Chris Lattner24943d22010-06-08 16:52:24 +00001//===-- Host.mm -------------------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#include <dlfcn.h>
11#include <libgen.h>
12#include <mach/mach.h>
13#include <mach-o/dyld.h>
14#include <signal.h>
15#include <stddef.h>
16#include <sys/sysctl.h>
17#include <unistd.h>
18
19#include <map>
20#include <string>
21
22#include <objc/objc-auto.h>
23
24#include <Foundation/Foundation.h>
25
Greg Clayton54e7afa2010-07-09 20:39:50 +000026#include "cfcpp/CFCBundle.h"
27#include "cfcpp/CFCReleaser.h"
28#include "cfcpp/CFCString.h"
Chris Lattner24943d22010-06-08 16:52:24 +000029
30#include "lldb/Host/Host.h"
31#include "lldb/Core/ArchSpec.h"
32#include "lldb/Core/ConstString.h"
33#include "lldb/Core/Error.h"
34#include "lldb/Core/FileSpec.h"
35#include "lldb/Core/Log.h"
36#include "lldb/Core/StreamString.h"
37#include "lldb/Host/Mutex.h"
38#include "lldb/Target/Process.h"
39#include "lldb/Target/Target.h"
40#include "lldb/Target/TargetList.h"
41#include "lldb/lldb-private-log.h"
42
43using namespace lldb;
44using namespace lldb_private;
45
46//------------------------------------------------------------------
47// Return the size in bytes of a page on the host system
48//------------------------------------------------------------------
49size_t
50Host::GetPageSize()
51{
52 return ::getpagesize();
53}
54
55
56//------------------------------------------------------------------
57// Returns true if the host system is Big Endian.
58//------------------------------------------------------------------
59ByteOrder
60Host::GetByteOrder()
61{
62 union EndianTest
63 {
64 uint32_t num;
65 uint8_t bytes[sizeof(uint32_t)];
66 } endian = { (uint16_t)0x11223344 };
67 switch (endian.bytes[0])
68 {
69 case 0x11: return eByteOrderLittle;
70 case 0x44: return eByteOrderBig;
71 case 0x33: return eByteOrderPDP;
72 }
73 return eByteOrderInvalid;
74}
75
76lldb::pid_t
77Host::GetCurrentProcessID()
78{
79 return ::getpid();
80}
81
82lldb::pid_t
83Host::GetCurrentThreadID()
84{
85 return ::mach_thread_self();
86}
87
88
89const ArchSpec &
90Host::GetArchitecture ()
91{
92 static ArchSpec g_host_arch;
93 if (!g_host_arch.IsValid())
94 {
95 uint32_t cputype, cpusubtype;
96 uint32_t is_64_bit_capable;
97 size_t len = sizeof(cputype);
98 if (::sysctlbyname("hw.cputype", &cputype, &len, NULL, 0) == 0)
99 {
100 len = sizeof(cpusubtype);
101 if (::sysctlbyname("hw.cpusubtype", &cpusubtype, &len, NULL, 0) == 0)
102 g_host_arch.SetArch(cputype, cpusubtype);
103
104 len = sizeof (is_64_bit_capable);
105 if (::sysctlbyname("hw.cpu64bit_capable", &is_64_bit_capable, &len, NULL, 0) == 0)
106 {
107 if (is_64_bit_capable)
108 {
109 if (cputype == CPU_TYPE_I386 && cpusubtype == CPU_SUBTYPE_486)
110 cpusubtype = CPU_SUBTYPE_I386_ALL;
111
112 cputype |= CPU_ARCH_ABI64;
113 }
114 }
115 }
116 }
117 return g_host_arch;
118}
119
120const ConstString &
121Host::GetVendorString()
122{
123 static ConstString g_vendor;
124 if (!g_vendor)
125 {
126 char ostype[64];
127 size_t len = sizeof(ostype);
128 if (::sysctlbyname("kern.ostype", &ostype, &len, NULL, 0) == 0)
129 g_vendor.SetCString (ostype);
130 }
131 return g_vendor;
132}
133
134const ConstString &
135Host::GetOSString()
136{
137 static ConstString g_os_string("apple");
138 return g_os_string;
139}
140
141const ConstString &
142Host::GetTargetTriple()
143{
144 static ConstString g_host_triple;
145 if (!(g_host_triple))
146 {
147 StreamString triple;
148 triple.Printf("%s-%s-%s",
149 GetArchitecture ().AsCString(),
150 GetVendorString().AsCString("apple"),
151 GetOSString().AsCString("darwin"));
152
153 std::transform (triple.GetString().begin(),
154 triple.GetString().end(),
155 triple.GetString().begin(),
156 ::tolower);
157
158 g_host_triple.SetCString(triple.GetString().c_str());
159 }
160 return g_host_triple;
161}
162
163class MacOSXDarwinThread
164{
165public:
166 MacOSXDarwinThread(const char *thread_name) :
167 m_pool (nil)
168 {
169 // Register our thread with the collector if garbage collection is enabled.
170 if (objc_collectingEnabled())
171 {
172#if MAC_OS_X_VERSION_MAX_ALLOWED <= MAC_OS_X_VERSION_10_5
173 // On Leopard and earlier there is no way objc_registerThreadWithCollector
174 // function, so we do it manually.
175 auto_zone_register_thread(auto_zone());
176#else
177 // On SnowLoepard and later we just call the thread registration function.
178 objc_registerThreadWithCollector();
179#endif
180 }
181 else
182 {
183 m_pool = [[NSAutoreleasePool alloc] init];
184 }
185
186
187 Host::SetThreadName (LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID, thread_name);
188 }
189
190 ~MacOSXDarwinThread()
191 {
192 if (m_pool)
193 [m_pool release];
194 }
195
196 static void PThreadDestructor (void *v)
197 {
198 delete (MacOSXDarwinThread*)v;
199 }
200
201protected:
202 NSAutoreleasePool * m_pool;
203private:
204 DISALLOW_COPY_AND_ASSIGN (MacOSXDarwinThread);
205};
206
207static pthread_once_t g_thread_create_once = PTHREAD_ONCE_INIT;
208static pthread_key_t g_thread_create_key = 0;
209
210static void
211InitThreadCreated()
212{
213 ::pthread_key_create (&g_thread_create_key, MacOSXDarwinThread::PThreadDestructor);
214}
215
Greg Claytonc0418152010-07-07 17:07:17 +0000216struct HostThreadCreateInfo
Chris Lattner24943d22010-06-08 16:52:24 +0000217{
218 std::string thread_name;
219 thread_func_t thread_fptr;
220 thread_arg_t thread_arg;
221
222 HostThreadCreateInfo (const char *name, thread_func_t fptr, thread_arg_t arg) :
223 thread_name (name ? name : ""),
224 thread_fptr (fptr),
225 thread_arg (arg)
226 {
227 }
228};
229
230static thread_result_t
231ThreadCreateTrampoline (thread_arg_t arg)
232{
233 HostThreadCreateInfo *info = (HostThreadCreateInfo *)arg;
234 Host::ThreadCreated (info->thread_name.c_str());
235 thread_func_t thread_fptr = info->thread_fptr;
236 thread_arg_t thread_arg = info->thread_arg;
237
238 Log * log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD);
239 if (log)
240 log->Printf("thread created");
241
242 delete info;
243 return thread_fptr (thread_arg);
244}
245
246lldb::thread_t
247Host::ThreadCreate
248(
249 const char *thread_name,
250 thread_func_t thread_fptr,
251 thread_arg_t thread_arg,
252 Error *error
253)
254{
255 lldb::thread_t thread = LLDB_INVALID_HOST_THREAD;
256
257 // Host::ThreadCreateTrampoline will delete this pointer for us.
258 HostThreadCreateInfo *info_ptr = new HostThreadCreateInfo (thread_name, thread_fptr, thread_arg);
259
260 int err = ::pthread_create (&thread, NULL, ThreadCreateTrampoline, info_ptr);
261 if (err == 0)
262 {
263 if (error)
264 error->Clear();
265 return thread;
266 }
267
268 if (error)
269 error->SetError (err, eErrorTypePOSIX);
270
271 return LLDB_INVALID_HOST_THREAD;
272}
273
274bool
275Host::ThreadCancel (lldb::thread_t thread, Error *error)
276{
277
278 int err = ::pthread_cancel (thread);
279 if (error)
280 error->SetError(err, eErrorTypePOSIX);
281 return err == 0;
282}
283
284bool
285Host::ThreadDetach (lldb::thread_t thread, Error *error)
286{
287 int err = ::pthread_detach (thread);
288 if (error)
289 error->SetError(err, eErrorTypePOSIX);
290 return err == 0;
291}
292
293bool
294Host::ThreadJoin (lldb::thread_t thread, thread_result_t *thread_result_ptr, Error *error)
295{
296 int err = ::pthread_join (thread, thread_result_ptr);
297 if (error)
298 error->SetError(err, eErrorTypePOSIX);
299 return err == 0;
300}
301
302void
303Host::ThreadCreated (const char *thread_name)
304{
305 ::pthread_once (&g_thread_create_once, InitThreadCreated);
306 if (g_thread_create_key)
307 {
308 ::pthread_setspecific (g_thread_create_key, new MacOSXDarwinThread(thread_name));
309 }
310}
311
312//------------------------------------------------------------------
313// Control access to a static file thread name map using a single
314// static function to avoid a static constructor.
315//------------------------------------------------------------------
316static const char *
317ThreadNameAccessor (bool get, lldb::pid_t pid, lldb::tid_t tid, const char *name)
318{
319
320 uint64_t pid_tid = ((uint64_t)pid << 32) | (uint64_t)tid;
321
322 static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
323 Mutex::Locker locker(&g_mutex);
324
325 typedef std::map<uint64_t, std::string> thread_name_map;
326 static thread_name_map g_thread_names;
327
328 if (get)
329 {
330 // See if the thread name exists in our thread name pool
331 thread_name_map::iterator pos = g_thread_names.find(pid_tid);
332 if (pos != g_thread_names.end())
333 return pos->second.c_str();
334 }
335 else
336 {
337 // Set the thread name
338 g_thread_names[pid_tid] = name;
339 }
340 return NULL;
341}
342
343
344
345const char *
346Host::GetSignalAsCString (int signo)
347{
348 switch (signo)
349 {
350 case SIGHUP: return "SIGHUP"; // 1 hangup
351 case SIGINT: return "SIGINT"; // 2 interrupt
352 case SIGQUIT: return "SIGQUIT"; // 3 quit
353 case SIGILL: return "SIGILL"; // 4 illegal instruction (not reset when caught)
354 case SIGTRAP: return "SIGTRAP"; // 5 trace trap (not reset when caught)
355 case SIGABRT: return "SIGABRT"; // 6 abort()
356#if defined(_POSIX_C_SOURCE)
357 case SIGPOLL: return "SIGPOLL"; // 7 pollable event ([XSR] generated, not supported)
358#else // !_POSIX_C_SOURCE
359 case SIGEMT: return "SIGEMT"; // 7 EMT instruction
360#endif // !_POSIX_C_SOURCE
361 case SIGFPE: return "SIGFPE"; // 8 floating point exception
362 case SIGKILL: return "SIGKILL"; // 9 kill (cannot be caught or ignored)
363 case SIGBUS: return "SIGBUS"; // 10 bus error
364 case SIGSEGV: return "SIGSEGV"; // 11 segmentation violation
365 case SIGSYS: return "SIGSYS"; // 12 bad argument to system call
366 case SIGPIPE: return "SIGPIPE"; // 13 write on a pipe with no one to read it
367 case SIGALRM: return "SIGALRM"; // 14 alarm clock
368 case SIGTERM: return "SIGTERM"; // 15 software termination signal from kill
369 case SIGURG: return "SIGURG"; // 16 urgent condition on IO channel
370 case SIGSTOP: return "SIGSTOP"; // 17 sendable stop signal not from tty
371 case SIGTSTP: return "SIGTSTP"; // 18 stop signal from tty
372 case SIGCONT: return "SIGCONT"; // 19 continue a stopped process
373 case SIGCHLD: return "SIGCHLD"; // 20 to parent on child stop or exit
374 case SIGTTIN: return "SIGTTIN"; // 21 to readers pgrp upon background tty read
375 case SIGTTOU: return "SIGTTOU"; // 22 like TTIN for output if (tp->t_local&LTOSTOP)
376#if !defined(_POSIX_C_SOURCE)
377 case SIGIO: return "SIGIO"; // 23 input/output possible signal
378#endif
379 case SIGXCPU: return "SIGXCPU"; // 24 exceeded CPU time limit
380 case SIGXFSZ: return "SIGXFSZ"; // 25 exceeded file size limit
381 case SIGVTALRM: return "SIGVTALRM"; // 26 virtual time alarm
382 case SIGPROF: return "SIGPROF"; // 27 profiling time alarm
383#if !defined(_POSIX_C_SOURCE)
384 case SIGWINCH: return "SIGWINCH"; // 28 window size changes
385 case SIGINFO: return "SIGINFO"; // 29 information request
386#endif
387 case SIGUSR1: return "SIGUSR1"; // 30 user defined signal 1
388 case SIGUSR2: return "SIGUSR2"; // 31 user defined signal 2
389 default:
390 break;
391 }
392 return NULL;
393}
394
395const char *
396Host::GetThreadName (lldb::pid_t pid, lldb::tid_t tid)
397{
398 const char *name = ThreadNameAccessor (true, pid, tid, NULL);
399 if (name == NULL)
400 {
401 // We currently can only get the name of a thread in the current process.
402#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
403 if (pid == Host::GetCurrentProcessID())
404 {
405 char pthread_name[1024];
406 if (::pthread_getname_np (::pthread_from_mach_thread_np (tid), pthread_name, sizeof(pthread_name)) == 0)
407 {
408 if (pthread_name[0])
409 {
410 // Set the thread in our string pool
411 ThreadNameAccessor (false, pid, tid, pthread_name);
412 // Get our copy of the thread name string
413 name = ThreadNameAccessor (true, pid, tid, NULL);
414 }
415 }
416 }
417#endif
418 }
419 return name;
420}
421
422void
423Host::SetThreadName (lldb::pid_t pid, lldb::tid_t tid, const char *name)
424{
425 lldb::pid_t curr_pid = Host::GetCurrentProcessID();
426 lldb::tid_t curr_tid = Host::GetCurrentThreadID();
427 if (pid == LLDB_INVALID_PROCESS_ID)
428 pid = curr_pid;
429
430 if (tid == LLDB_INVALID_THREAD_ID)
431 tid = curr_tid;
432
433#if MAC_OS_X_VERSION_MAX_ALLOWED > MAC_OS_X_VERSION_10_5
434 // Set the pthread name if possible
435 if (pid == curr_pid && tid == curr_tid)
436 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000437 ::pthread_setname_np (name);
Chris Lattner24943d22010-06-08 16:52:24 +0000438 }
439#endif
440 ThreadNameAccessor (false, pid, tid, name);
441}
442
443FileSpec
444Host::GetProgramFileSpec ()
445{
446 static FileSpec g_program_filepsec;
447 if (!g_program_filepsec)
448 {
Greg Clayton54e7afa2010-07-09 20:39:50 +0000449 char program_fullpath[PATH_MAX];
Chris Lattner24943d22010-06-08 16:52:24 +0000450 // If DST is NULL, then return the number of bytes needed.
Greg Clayton54e7afa2010-07-09 20:39:50 +0000451 uint32_t len = sizeof(program_fullpath);
452 int err = _NSGetExecutablePath (program_fullpath, &len);
Chris Lattner24943d22010-06-08 16:52:24 +0000453 if (err == 0)
Greg Clayton54e7afa2010-07-09 20:39:50 +0000454 g_program_filepsec.SetFile (program_fullpath);
455 else if (err == -1)
456 {
457 char *large_program_fullpath = (char *)::malloc (len + 1);
458
459 err = _NSGetExecutablePath (large_program_fullpath, &len);
460 if (err == 0)
461 g_program_filepsec.SetFile (large_program_fullpath);
462
463 ::free (large_program_fullpath);
464 }
Chris Lattner24943d22010-06-08 16:52:24 +0000465 }
466 return g_program_filepsec;
467}
468
469
470FileSpec
471Host::GetModuleFileSpecForHostAddress (const void *host_addr)
472{
473 FileSpec module_filespec;
474 Dl_info info;
475 if (::dladdr (host_addr, &info))
476 {
477 if (info.dli_fname)
478 module_filespec.SetFile(info.dli_fname);
479 }
480 return module_filespec;
481}
482
483
484bool
485Host::ResolveExecutableInBundle (FileSpec *file)
486{
487 if (file->GetFileType () == FileSpec::eFileTypeDirectory)
488 {
489 char path[PATH_MAX];
490 if (file->GetPath(path, sizeof(path)))
491 {
492 CFCBundle bundle (path);
493 CFCReleaser<CFURLRef> url(bundle.CopyExecutableURL ());
494 if (url.get())
495 {
496 if (::CFURLGetFileSystemRepresentation (url.get(), YES, (UInt8*)path, sizeof(path)))
497 {
498 file->SetFile(path);
499 return true;
500 }
501 }
502 }
503 }
504 return false;
505}
506
Greg Claytonc0418152010-07-07 17:07:17 +0000507struct MonitorInfo
Chris Lattner24943d22010-06-08 16:52:24 +0000508{
Greg Clayton54e7afa2010-07-09 20:39:50 +0000509 uint32_t handle;
Chris Lattner24943d22010-06-08 16:52:24 +0000510 pthread_t thread;
511 Host::MonitorChildProcessCallback callback;
512 void *callback_baton;
513 bool monitor_signals;
514};
515
516typedef std::multimap<lldb::pid_t, MonitorInfo> MonitorInfoMap;
517static pthread_mutex_t g_monitor_map_mutex = PTHREAD_MUTEX_INITIALIZER;
518typedef lldb::SharedPtr<MonitorInfoMap>::Type MonitorInfoMapSP;
519
520static MonitorInfoMapSP&
521GetMonitorMap (bool can_create)
522{
523 static MonitorInfoMapSP g_monitor_map_sp;
524 if (can_create && g_monitor_map_sp.get() == NULL)
525 {
526 g_monitor_map_sp.reset (new MonitorInfoMap);
527 }
528 return g_monitor_map_sp;
529}
530
531static Predicate<bool>&
532GetChildProcessPredicate ()
533{
534 static Predicate<bool> g_has_child_processes;
535 return g_has_child_processes;
536}
537
538static void *
539MonitorChildProcessThreadFunction (void *arg);
540
541static pthread_t g_monitor_thread;
542
543uint32_t
544Host::StartMonitoringChildProcess
545(
546 MonitorChildProcessCallback callback,
547 void *callback_baton,
548 lldb::pid_t pid,
549 bool monitor_signals
550)
551{
552 static uint32_t g_handle = 0;
553 if (callback)
554 {
555 Mutex::Locker locker(&g_monitor_map_mutex);
556 if (!g_monitor_thread)
557 {
Greg Claytonf2a4d2e2010-07-06 20:27:00 +0000558 lldb::pid_t wait_pid = -1;
Chris Lattner24943d22010-06-08 16:52:24 +0000559 g_monitor_thread = ThreadCreate ("<lldb.host.wait4>",
560 MonitorChildProcessThreadFunction,
561 &wait_pid,
562 NULL);
563 if (g_monitor_thread)
564 {
565 //Host::ThreadDetach (g_monitor_thread, NULL);
566 }
567 }
568
569 if (g_monitor_thread)
570 {
571 MonitorInfo info = { ++g_handle, 0, callback, callback_baton, monitor_signals };
572 MonitorInfoMapSP monitor_map_sp (GetMonitorMap (true));
573 if (monitor_map_sp)
574 {
575 monitor_map_sp->insert(std::make_pair(pid, info));
576 GetChildProcessPredicate ().SetValue (true, eBroadcastOnChange);
577 return info.handle;
578 }
579 }
580 }
581 return 0;
582}
583
584bool
585Host::StopMonitoringChildProcess (uint32_t handle)
586{
587 Mutex::Locker locker(&g_monitor_map_mutex);
588 MonitorInfoMapSP monitor_map_sp (GetMonitorMap (false));
589 if (monitor_map_sp)
590 {
591 MonitorInfoMap::iterator pos, end = monitor_map_sp->end();
592 for (pos = monitor_map_sp->end(); pos != end; ++pos)
593 {
594 if (pos->second.handle == handle)
595 {
596 monitor_map_sp->erase(pos);
597 return true;
598 }
599 }
600 }
601 return false;
602}
603
604
605//------------------------------------------------------------------
606// Scoped class that will disable thread canceling when it is
607// constructed, and exception safely restore the previous value it
608// when it goes out of scope.
609//------------------------------------------------------------------
610class ScopedPThreadCancelDisabler
611{
612public:
613
614 ScopedPThreadCancelDisabler()
615 {
616 // Disable the ability for this thread to be cancelled
617 int err = ::pthread_setcancelstate (PTHREAD_CANCEL_DISABLE, &m_old_state);
618 if (err != 0)
619 m_old_state = -1;
620
621 }
622
623 ~ScopedPThreadCancelDisabler()
624 {
625 // Restore the ability for this thread to be cancelled to what it
626 // previously was.
627 if (m_old_state != -1)
628 ::pthread_setcancelstate (m_old_state, 0);
629 }
630private:
631 int m_old_state; // Save the old cancelability state.
632};
633
634
635
636static void *
637MonitorChildProcessThreadFunction (void *arg)
638{
639 Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS);
640 const char *function = __FUNCTION__;
641 if (log)
642 log->Printf ("%s (arg = %p) thread starting...", function, arg);
643
Greg Claytonf2a4d2e2010-07-06 20:27:00 +0000644 const lldb::pid_t wait_pid = -1;//*((pid_t*)arg);
Chris Lattner24943d22010-06-08 16:52:24 +0000645 int status = -1;
646 const int options = 0;
647 struct rusage *rusage = NULL;
648 while (1)
649 {
650 if (log)
651 log->Printf("%s ::wait4 (pid = %i, &status, options = %i, rusage = %p)...", function, wait_pid, options, rusage);
652
653 // Wait for all child processes
654 ::pthread_testcancel ();
655 lldb::pid_t pid = ::wait4 (wait_pid, &status, options, rusage);
656 ::pthread_testcancel ();
657
658 if (pid < 0)
659 {
660 // No child processes to watch wait for the mutex to be cleared
661
662 // Scope for "locker"
663 {
664 ScopedPThreadCancelDisabler pthread_cancel_disabler;
665
666 // First clear out all monitor entries since we have no processes
667 // to watch.
668 Mutex::Locker locker(&g_monitor_map_mutex);
669 // Since we don't have any child processes, we can safely clear
670 // anyone with a valid pid.
671 MonitorInfoMapSP monitor_map_sp(GetMonitorMap (false));
672 if (monitor_map_sp)
673 {
674 MonitorInfoMap::iterator pos = monitor_map_sp->begin();
675 while (pos != monitor_map_sp->end())
676 {
677 // pid value of 0 and -1 are special (see man page on wait4...)
678 if (pos->first > 0)
679 {
680 MonitorInfoMap::iterator next_pos = pos; ++next_pos;
681 monitor_map_sp->erase (pos, next_pos);
682 pos = next_pos;
683 }
684 else
685 ++pos;
686 }
687 }
688 }
689
690 if (log)
691 log->Printf("%s no child processes, wait for some...", function);
692 GetChildProcessPredicate ().SetValue (false, eBroadcastNever);
693 ::pthread_testcancel();
694 GetChildProcessPredicate ().WaitForValueEqualTo (true);
695 if (log)
696 log->Printf("%s resuming monitoring of child processes.", function);
697
698 }
699 else
700 {
701 ScopedPThreadCancelDisabler pthread_cancel_disabler;
702 bool exited = false;
703 int signal = 0;
704 int exit_status = 0;
705 const char *status_cstr = NULL;
706 if (WIFSTOPPED(status))
707 {
708 signal = WSTOPSIG(status);
709 status_cstr = "STOPPED";
710 }
711 else if (WIFEXITED(status))
712 {
713 exit_status = WEXITSTATUS(status);
714 status_cstr = "EXITED";
715 exited = true;
716 }
717 else if (WIFSIGNALED(status))
718 {
719 signal = WTERMSIG(status);
720 status_cstr = "SIGNALED";
721 exited = true;
722 exit_status = -1;
723 }
724 else
725 {
726 status_cstr = "(???)";
727 }
728
729 if (log)
730 log->Printf ("%s ::wait4 (pid = %i, &status, options = %i, rusage = %p) => pid = %i, status = 0x%8.8x (%s), signal = %i, exit_state = %i",
731 function,
732 wait_pid,
733 options,
734 rusage,
735 pid,
736 status,
737 status_cstr,
738 signal,
739 exit_status);
740
741 // Scope for mutex locker
742 {
743 // Notify anyone listening to this process
744 Mutex::Locker locker(&g_monitor_map_mutex);
745 MonitorInfoMapSP monitor_map_sp(GetMonitorMap (false));
746 if (monitor_map_sp)
747 {
748 std::pair<MonitorInfoMap::iterator, MonitorInfoMap::iterator> range;
749 range = monitor_map_sp->equal_range(pid);
750 MonitorInfoMap::iterator pos;
751 for (pos = range.first; pos != range.second; ++pos)
752 {
753 if (exited || (signal != 0 && pos->second.monitor_signals))
754 {
755 bool callback_return = pos->second.callback (pos->second.callback_baton, pid, signal, exit_status);
756
757 if (exited || callback_return)
758 {
759 // Make this entry as needing to be removed by
760 // setting its handle to zero
761 pos->second.handle = 0;
762 }
763 }
764 }
765
766 // Remove any entries that requested to be removed or any
767 // entries for child processes that did exit. We know this
768 // because we changed the handles to an invalid value.
769 pos = monitor_map_sp->begin();
770 while (pos != monitor_map_sp->end())
771 {
772 if (pos->second.handle == 0)
773 {
774 MonitorInfoMap::iterator next_pos = pos; ++next_pos;
775 monitor_map_sp->erase (pos, next_pos);
776 pos = next_pos;
777 }
778 else
779 ++pos;
780 }
781 }
782 }
783 }
784 }
785
786 if (log)
787 log->Printf ("ProcessMacOSX::%s (arg = %p) thread exiting...", __FUNCTION__, arg);
788
789 g_monitor_thread = NULL;
790 return NULL;
791}
792
793void
794Host::WillTerminate ()
795{
796 if (g_monitor_thread != NULL)
797 {
798 ThreadCancel (g_monitor_thread, NULL);
799 GetChildProcessPredicate ().SetValue (true, eBroadcastAlways);
800 ThreadJoin(g_monitor_thread, NULL, NULL);
801 g_monitor_thread = NULL;
802 }
803}
804