PX4編譯過程解讀程式碼1
阿新 • • 發佈:2019-01-24
第一個編譯檔案DriverFramework.cpp
位置:src/lib/DriverFraamework/framework/src/DriverFramework.cpp
#define SHOW_STATS 0
namespace DriverFramework //名稱空間DriverFramework
{
型別
class HRTWorkQueue : public DisableCopy //HRTWorkQueue公有繼承DisableCopy { public: static HRTWorkQueue &instance(); int initialize(); //初始化 void finalize(); void scheduleWorkItem(WorkHandle &wh); void shutdown(); void enableStats(bool enable); static void *process_trampoline(void * /*arg*/); private: HRTWorkQueue() = default; ~HRTWorkQueue() = default; void process(); bool m_enable_stats = false; SyncObj m_reschedule; }; }; using namespace DriverFramework;
Global Variables 全域性變數
namespace DriverFramework
{
RunStatus *g_run_status = nullptr; //定義*g_run_status為空指標,不會發生二義性
};
靜態變數
static pthread_t g_tid;
static SyncObj *g_framework; //QuRT C++ compiler不支援靜態類的初始化
靜態函式
static uint64_t TsToAbstime(struct timespec *ts) //TsToAbstime表示得到系統實時時鐘的絕對時間,timespec就是實時時間;若獲得絕對時間成功,return 0,否則返回非零 { uint64_t result = (uint64_t)(ts->tv_sec) * 1000000UL; result += ts->tv_nsec / 1000; return result; } static uint64_t starttime = 0; //靜態常量開始時間為零 static void initStartTime() //靜態初始化開始時間函式 { struct timespec ts = {}; //實際時間為空陣列 int ret = absoluteTime(ts); //將絕對時間值賦值給ret if (ret != 0) { 如果ret不為零,列印“錯誤:絕對時間返回為ret” printf("ERROR: absoluteTime returned (%d)\n", ret); return; } starttime = TsToAbstime(&ts); //將獲得的絕對時間賦值給starttime } static inline uint64_t getStartTime() //行內函數,呼叫時會檢查函式傳參是否正確,也不需要預編譯,獲得starttime { return starttime; }
全域性函式
//不要在這裡使用DF_LOG_XXX,因為它會導致遞迴迴圈 uint64_t DriverFramework::offsetTime() //實現偏移量時間offsetTime函式 { struct timespec ts = {}; //實際時間陣列為空 int ret = absoluteTime(ts); //將得到的絕對時間賦值給整形ret if (ret != 0) { printf("ERROR: absoluteTime returned (%d)", ret); return 0; } // 時間單位是微秒 uint64_t result = TsToAbstime(&ts) - getStartTime(); //得到的結果=絕對時間-開始得到的時間 return result; } timespec DriverFramework::offsetTimeToAbsoluteTime(uint64_t offset_time) //實現絕對時間偏移量函式 { struct timespec ts = {}; uint64_t abs_time = offset_time + getStartTime(); //絕對時間=時間偏移量+得到開始時間 ts.tv_sec = abs_time / 1000000; //ts時間的秒計數的值 ts.tv_nsec = (abs_time % 1000000) * 1000; //ts時間的納秒計數的值 return ts; } #if DF_ENABLE_BACKTRACE void DriverFramework::backtrace() //backtrace()函式用來獲取程式中當前函式的回溯資訊 { void *buffer[10]; //backtrace()函式的返回值為buffer中的條目數量 char **callstack; int bt_size; //引數size指定了buffer中可存放的返回地址的數量 int idx; bt_size = ::backtrace(buffer, 10); callstack = ::backtrace_symbols(buffer, bt_size); //backtrace_symbols()函式可以將每一個返回值都翻譯成“函式名+函式內偏移量+函式返回值” DF_LOG_INFO("Backtrace: %d", bt_size); for (idx = 0; idx < bt_size; idx++) { DF_LOG_INFO("%s", callstack[idx]); } free(callstack); //經過翻譯後的函式回溯資訊放到backtrace_symbols()的返回值中,如果失敗則返回NULL。需要注意,返回值本身是在backtrace_symbols()函式內部進行malloc的,所以必須在後續顯式地free掉。 } #endif
類實現方式
//RunStatus執行狀態
bool RunStatus::check()
{
m_lock.lock();
bool ret = m_run;
m_lock.unlock();
return ret;
}
void RunStatus::terminate()
{
m_lock.lock();
m_run = false;
m_lock.unlock();
}
//框架
void Framework::shutdown()
{
// 釋放HRTWorkQueue資源
HRTWorkQueue::instance().finalize();
// 釋放WorkMgr資源
WorkMgr::finalize();
// 釋放DevMgr資源
DevMgr::finalize();
// 允許框架退出
g_framework->lock();
g_framework->signal();
g_framework->unlock();
}
int Framework::initialize()
{
initStartTime(); // 必須在呼叫任何其他計時方法之前初始化
DF_LOG_DEBUG("Framework::initialize");
g_framework = new SyncObj;
if (!g_framework) {
DF_LOG_ERR("ERROR: falled to allocate g_framework");
return -1;
}
g_run_status = new RunStatus;
if (!g_run_status) {
DF_LOG_ERR("g_run_status allocation failed");
return -2;
}
struct timespec ts = {};
int ret = absoluteTime(ts);
if (ret != 0) {
DF_LOG_ERR("ERROR: absoluteTime returned (%d)", ret);
return -4;
}
ret = HRTWorkQueue::instance().initialize();
if (ret < 0) {
return ret - 10;
}
DF_LOG_DEBUG("Calling DevMgr::initialize");
ret = DevMgr::initialize();
if (ret < 0) {
return ret - 20;
}
DF_LOG_DEBUG("Calling WorkMgr::initialize");
ret = WorkMgr::initialize();
if (ret < 0) {
return ret - 30;
}
return 0;
}
void Framework::waitForShutdown()
{
// 阻止直到請求關閉
g_framework->lock();
g_framework->waitOnSignal(0);
g_framework->unlock();
delete g_framework;
g_framework = nullptr;
}
#ifndef __DF_QURT
// pthread_setschedparam似乎不適用於QURT,在DSP上面的RTOS是QuRT。
static void show_sched_settings()
{
int policy;
struct sched_param param {};
int ret = pthread_getschedparam(pthread_self(), &policy, ¶m); //得到執行緒的許可權,pthread_self()是獲得的執行緒ID。policy執行緒的排程, SCHED_FIFO(先入先出),SCHED_RR(迴圈),SCHED_OTHER(實現定義的方法)。
if (ret != 0) {
DF_LOG_ERR("pthread_getschedparam failed (%d)", ret);
}
DF_LOG_DEBUG("pthread info: policy=%s priority=%d",
(policy == SCHED_OTHER) ? "SCHED_OTHER" :
(policy == SCHED_FIFO) ? "SCHED_FIFO" :
(policy == SCHED_RR) ? "SCHED_RR" :
"UNKNOWN",
param.sched_priority);
}
static int setRealtimeSched() //設定實時排程
{
int policy = SCHED_FIFO; //排程策略採用先進先出
sched_param param {};
param.sched_priority = 10; //優先順序設定為10
int ret = pthread_setschedparam(pthread_self(), policy, ¶m); //設定執行緒的許可權
show_sched_settings();
return ret;
}
#endif
void *HRTWorkQueue::process_trampoline(void *arg)
{
DF_LOG_DEBUG("HRTWorkQueue::process_trampoline");
#ifndef __DF_QURT
int ret = setRealtimeSched();
if (ret != 0) {
DF_LOG_ERR("WARNING: setRealtimeSched failed (not run as root?)");
}
#endif
#ifdef __DF_LINUX
prctl(PR_SET_NAME, "DFWorker"); //設定執行緒名稱為DFWorker
#endif
DF_LOG_DEBUG("process_trampoline %d", ret);
instance().process();
return nullptr;
}
HRTWorkQueue &HRTWorkQueue::instance()
{
static HRTWorkQueue *instance = nullptr;
if (!instance) {
instance = new HRTWorkQueue();
}
return *instance;
}
int HRTWorkQueue::initialize()
{
DF_LOG_DEBUG("HRTWorkQueue::initialize");
pthread_attr_t attr {};
int ret = pthread_attr_init(&attr);
if (ret != 0) {
DF_LOG_ERR("pthread_attr_init failed");
return -1;
}
#ifdef __DF_QURT
// 嘗試設定堆疊大小。 此堆疊大小稍後在感測器驅動程式中的_measure()呼叫中使用,至少在QURT上使用。
const size_t stacksize = 3072;
if (pthread_attr_setstacksize(&attr, stacksize) != 0) {
DF_LOG_ERR("failed to set stack size of %lu bytes", stacksize);
return -2;
}
#endif
// 建立高優先順序工作執行緒
if (pthread_create(&g_tid, &attr, process_trampoline, nullptr)) {
return -3;
}
DF_LOG_DEBUG("pthread_create success");
return 0;
}
void HRTWorkQueue::finalize()
{
DF_LOG_DEBUG("HRTWorkQueue::finalize");
shutdown();
// 等待工作佇列執行緒退出
pthread_join(g_tid, nullptr);
}
void HRTWorkQueue::scheduleWorkItem(WorkHandle &wh)
{
DF_LOG_DEBUG("HRTWorkQueue::scheduleWorkItem (%p)", &wh);
// 控制代碼已知有效
int ret = WorkItems::schedule(wh.m_handle);
DF_LOG_DEBUG("WorkItems::schedule %d", ret);
if (ret == 0) {
wh.m_errno = 0;
m_reschedule.lock();
m_reschedule.signal();
m_reschedule.unlock();
} else if (ret == EBADF) {
wh.m_errno = EBADF;
wh.m_handle = -1;
} else {
wh.m_errno = ret;
}
}
void HRTWorkQueue::shutdown()
{
DF_LOG_DEBUG("HRTWorkQueue::shutdown");
if (g_run_status) {
g_run_status->terminate();
}
m_reschedule.lock();
m_reschedule.signal();
m_reschedule.unlock();
}
void HRTWorkQueue::process()
{
DF_LOG_DEBUG("HRTWorkQueue::process");
uint64_t next;
uint64_t now;
while (g_run_status && g_run_status->check()) {
now = offsetTime();
// 如果沒有預定,每10秒喚醒一次
next = now + 10000000;
WorkItems::processExpiredWorkItems(next);
now = offsetTime();
DF_LOG_DEBUG("now=%" PRIu64, now);
#ifdef __DF_QURT
// 以適應平臺中程序睡眠的不準確性
if (next > now + 200) {
#else
if (next > now) {
#endif
uint64_t wait_time_usec = next - now;
DF_LOG_DEBUG("HRTWorkQueue::process waiting for work (%" PRIi64 "usec)", wait_time_usec);
// 等待直到下個專案到期或者直到有新的專案被安排
m_reschedule.lock();
m_reschedule.waitOnSignal(wait_time_usec);
m_reschedule.unlock();
DF_LOG_DEBUG("HRTWorkQueue::process done wait");
}
DF_LOG_DEBUG("HRTWorkQueue::process not waiting for work");
}
};
// 在這篇文章中才能訪問HRTWorkQueue::scheduleWorkItem
int WorkMgr::schedule(DriverFramework::WorkHandle &wh)
{
DF_LOG_DEBUG("WorkMgr::schedule");
HRTWorkQueue::instance().scheduleWorkItem(wh);
return (wh.m_errno == 0) ? 0 : -1;
}