X-Git-Url: https://git.saurik.com/apple/system_cmds.git/blobdiff_plain/1a7e3f61d38d679bba59130891c2031b5a0092b6..bd6521f0fc816ab056bc71376f9706a69b3b52c1:/KDBG/MachineThread.hpp diff --git a/KDBG/MachineThread.hpp b/KDBG/MachineThread.hpp new file mode 100644 index 0000000..1d93ba7 --- /dev/null +++ b/KDBG/MachineThread.hpp @@ -0,0 +1,124 @@ +// +// MachineThread.hpp +// KDBG +// +// Created by James McIlree on 10/26/12. +// Copyright (c) 2014 Apple. All rights reserved. +// + +template class MachineProcess; + +enum class kMachineThreadFlag : std::uint32_t { + CreatedByPreviousMachineState = 0x00000001, + CreatedByThreadMap = 0x00000002, + CreatedByTraceDataNewThread = 0x00000004, + CreatedByUnknownTidInTrace = 0x00000008, + CreatedByForkExecEvent = 0x00000010, + CreatedByExecEvent = 0x00000020, + IsMain = 0x00000040, + IsIdle = 0x00000080, + TraceTerminated = 0x00000200, // Set when a MACH_THREAD_TERMINATED is seen. This is definitive, no further trace events should reference this thread. +}; + +template class Machine; +template class JetsamActivity; +template class MachineVoucher; + +template +class MachineThread { + protected: + uint32_t _flags; + typename SIZE::ptr_t _tid; // We're unlikely to ever look at K64 on a 32 bit machine, put this here as best chance to not increase struct size with useless padding bytes. + MachineProcess* _process; + AbsInterval _timespan; + AbsTime _begin_blocked; + AbsTime _begin_vm_fault; + AbsTime _begin_jetsam_activity; + uint32_t _begin_jetsam_activity_type; + std::vector _blocked; + std::vector _vm_faults; + std::vector _jetsam_activity; + std::vector> _vouchers_by_time; + + // + // Mutable API + // + friend class Machine; + friend class MachineProcess; + + MachineProcess& mutable_process() { return *_process; } + + void set_flags(kMachineThreadFlag flags) { _flags |= (uint32_t)flags; } + void clear_flags(kMachineThreadFlag flags) { _flags &= ~(uint32_t)flags; } + bool is_flag_set(kMachineThreadFlag flag) const { return (_flags & (uint32_t)flag) > 0; } + + // This can be discovered after the thread is created. + void set_is_idle_thread(); + void set_trace_terminated(AbsTime timestamp); + + void set_voucher(MachineVoucher* voucher, AbsTime timestamp); + + // + // NOTE! Unrunnable/blocked isn't quite exact; it doesn't match + // the scheduler view of unrunnable/blocked. + // + // 1) If you're not blocked, you're runnable + // 2) A thread is considered "blocked" if the cpu it is on goes idle. + // + void make_runnable(AbsTime timestamp); + void make_unrunnable(AbsTime timestamp); + + void begin_vm_fault(AbsTime timestamp); + void end_vm_fault(AbsTime timestamp); + + void begin_jetsam_activity(uint32_t type, AbsTime timestamp); + void end_jetsam_activity(uint32_t type, AbsTime timestamp); + + void add_io_activity(AbsInterval interval, uint32_t code, uint32_t page_count); + + AbsTime blocked_in_timespan(AbsInterval timespan) const; + AbsTime next_blocked_after(AbsTime timestamp) const; + + // This is called after all events have been processed, to flush any pending state + void post_initialize(AbsTime last_machine_timestamp); + + public: + MachineThread(MachineProcess* process, typename SIZE::ptr_t tid, MachineVoucher* initial_voucher, AbsTime create_timestamp, kMachineThreadFlag flags) : + _flags((uint32_t)flags), + _tid(tid), + _process(process), + _timespan(create_timestamp, AbsTime(0)), + _begin_jetsam_activity_type(0) + { + ASSERT(_tid != 0, "Sanity"); + ASSERT(_process, "Sanity"); + ASSERT(initial_voucher, "Sanity"); + + _vouchers_by_time.emplace_back(initial_voucher, AbsInterval(create_timestamp, AbsTime::END_OF_TIME - create_timestamp)); + } + + typename SIZE::ptr_t tid() const { return _tid; } + AbsInterval timespan() const { return _timespan; } + const MachineProcess& process() const { return *_process; } + uint32_t flags() const { return _flags; } + + const MachineVoucher* voucher(AbsTime timestamp) const; + const MachineVoucher* last_voucher() const; + + const std::vector& vm_faults() const { return _vm_faults; } + const std::vector& jetsam_activity() const { return _jetsam_activity; } + + bool is_created_by_previous_machine_state() const { return is_flag_set(kMachineThreadFlag::CreatedByPreviousMachineState); } + bool is_created_by_thread_map() const { return is_flag_set(kMachineThreadFlag::CreatedByThreadMap); } + bool is_created_by_trace_data_new_thread() const { return is_flag_set(kMachineThreadFlag::CreatedByTraceDataNewThread); } + bool is_created_by_unknown_tid_in_trace() const { return is_flag_set(kMachineThreadFlag::CreatedByUnknownTidInTrace); } + bool is_created_by_fork_exec() const { return is_flag_set(kMachineThreadFlag::CreatedByForkExecEvent); } + bool is_created_by_exec() const { return is_flag_set(kMachineThreadFlag::CreatedByExecEvent); } + + bool is_idle_thread() const { return is_flag_set(kMachineThreadFlag::IsIdle); } + bool is_main_thread() const { return is_flag_set(kMachineThreadFlag::IsMain); } + + bool is_trace_terminated() const { return is_flag_set(kMachineThreadFlag::TraceTerminated); } + + DEBUG_ONLY(void validate() const;) +};