#define min(x,y) ({ \
typeof(x) _x = (x); \
typeof(y) _y = (y); \node
(void) (&_x == &_y); \ // 爲了當x,y 是表達式的時候,編譯報錯如i++,j++; 或者是 x y 不是同一個類型 的時候,不一樣的指針比較編譯警告。linux
_x < _y ? _x : _y; })android
// android binderc#
struct binder_buffer {
struct list_head entry; /* free and allocated entries by address */
struct rb_node rb_node; /* free entry by size or allocated entry */
/* by address */
unsigned free:1;
unsigned allow_user_free:1;
unsigned async_transaction:1;
unsigned debug_id:29;
struct binder_transaction *transaction;
#ifdef BINDER_MONITOR
struct binder_transaction_log_entry *log_entry;
#endif
struct binder_node *target_node;
size_t data_size;
size_t offsets_size;
uint8_t data[0]; // 得到一個內存地址標記並能夠節省沒必要要的存儲空間
};async
buffer = rb_entry(n, struct binder_buffer, rb_node);
tmp_size = binder_buffer_size(target_proc, buffer);// 計算 buffer 的容量大小。因爲內存是線性增加分配的,而且在entry 中按地址排列,因此 由 下一個buffer 的地址- 這個buffer的data 就是 當前buffer大小。函數
static size_t binder_buffer_size(struct binder_proc *proc,
struct binder_buffer *buffer)
{
if (list_is_last(&buffer->entry, &proc->buffers))
//proc->buffer_size = vma->vm_end - vma->vm_startpost
return proc->buffer + proc->buffer_size - (void *)buffer->data;性能
else
return (size_t)list_entry(buffer->entry.next,
struct binder_buffer, entry) - (size_t)buffer->data;
}ui
// 位域,不是全部的編譯器都支持這種用法,對於有些編譯器一個位域不能跨字節,不夠的話,從下個字節開始。spa
struct _a
{
int a:1
int :2 /*該2位不能使用*/
int b:3
int c:2
};
struct _b
{
unsigned a:4
unsigned :0 /*空域*/
unsigned b:4 /*從下一單元開始存放*/
unsigned c:4
}
// 紅黑樹的實現,紅黑樹經過着色保持到NULL 節點最長的路徑最可能是最短的路徑兩倍。以達到普通二叉樹與平衡二叉樹的折中選擇。
着色只有紅黑兩種,能夠用一位,來表示;tree_node 的三要素 parent ,child_left, child_right ,能夠確定
每一個節點都有惟一的parent;看下面的 struct rb_node 是 (aligned(sizeof(long))) 對齊的;這樣指向 parent node 的地址parent 兩位最低權值的bit 位爲00是肯定的,沒有有效的信息熵,能夠用來承載rb_node 的color 信息。因此__rb_parent_color纔會有下面 rb_parent 宏 ,以及rb_set_parent ,rb_set_parent_color 函數。
struct rb_node {
unsigned long __rb_parent_color;
struct rb_node *rb_right;
struct rb_node *rb_left;
} __attribute__((aligned(sizeof(long))));
#define rb_parent(r) ((struct rb_node *)((r)->__rb_parent_color & ~3)
struct rb_root {
struct rb_node *rb_node;
};
static inline void rb_set_parent(struct rb_node *rb, struct rb_node *p)
{
rb->__rb_parent_color = rb_color(rb) | (unsigned long)p;
}
static inline void rb_set_parent_color(struct rb_node *rb,
struct rb_node *p, int color)
{
rb->__rb_parent_color = (unsigned long)p | color;
}
/*
* These are used to make use of C type-checking..
*/
typedef struct { unsigned long next; } next;
tracepoint.h
linux 中的鉤子,linux 會把tracepoint 儲存在特殊的連接segment 中(__tracepoints*)
tracepoint 定義是全局的因此在內核,moduler中是惟一標誌的,因此建議以subsystem_event形式命名。
tracepoint 用到JUMPLABLE 技術來提升性能具體就是static_key。具體是動態的修改asm 標籤使得nop 指令變成jmp lable ,這樣是爲了解決指令預取的命中率,這種方式對二進制修改不多進一個指令替換。
這一切在kernel中的用法以下:
#define JUMP_LABEL_INITIAL_NOP ".byte 0xe9 /n/t .long 0/n/t"
#define JUMP_LABEL(key, label) /
do { /
1 asm goto("1:" /
2 JUMP_LABEL_INITIAL_NOP /
3 ".pushsection __jump_table, /"a/" /n/t"/
4 _ASM_PTR "1b, %l[" #label "], %c0 /n/t" /
5 ".popsection /n/t" /
6 : : "i" (key) : : label); /
} while (0)
第一行的「1」是一個標號,該標號後的代碼執行的內容就是nop-第二行,第三行從新開始了一個section,這樣的意義很大,下面的三元組: [instruction address] [jump target] [tracepoint key]的二進制代碼就不會緊接着標號1(nop)了,這個三元組就是jump label機制的核心,指示了全部可能跳轉到的標號,這裏的技巧在於標號1,標號1也做爲一個合法的可能跳轉到的標號存在,和標號label是並列的,由 於pushsection和popsection的存在,上面的代碼彙編結果看起來是下面這樣:
修改後對應的彙編效果例如
修改前
.text
1:
nop
no-trace-code
ret ;因爲是ret 指令後面的指令不用預取。
trace:
trace-code
...
修改後
.text
1:
jmp trace
no-trace-code
ret
trace:
trace-code
...
tracepoint 的過程是:
1,調用__DECLARE_TRACE(name) 申明tracepoint 爲__tracepoint_##name,而且定義
trace_##name(proto) ,register_trace_##name() unregister_trace_##name().
重點講解兩個函數:
trace_##name(proto) 中是根據配置是否須要trace調用原型爲proto的鉤子程序。register_trace_##name()中調用tracepoint_probe_register會把咱們實現的鉤子程序指針,參數付給 __tracepoint##name 變量中的funcs
2,調用register_trace_##name() 把咱們實現的鉤子和tracepoint 聯繫起來
3,在調用點調用trace_##name(proto) 來回調tracepoint的鉤子函數,實現調試目的。
4,unregister_trace_##name()
26struct tracepoint_func { 27 void *func; 28 void *data; 29}; 30 31struct tracepoint { 32 const char *name; /* Tracepoint name */ 33 struct static_key key; 34 void (*regfunc)(void); 35 void (*unregfunc)(void); 36 struct tracepoint_func __rcu *funcs; 37}; 38
102#define TP_PROTO(args...) args 103#define TP_ARGS(args...) args 104#define TP_CONDITION(args...) args
#define __DO_TRACE(tp, proto, args, cond, prercu, postrcu) \ 119 do { \ 120 struct tracepoint_func *it_func_ptr; \ 121 void *it_func; \ 122 void *__data; \ 123 \ 124 if (!(cond)) \ 125 return; \ 126 prercu; \ 127 rcu_read_lock_sched_notrace(); \ 128 it_func_ptr = rcu_dereference_sched((tp)->funcs); \ 129 if (it_func_ptr) { \ 130 do { \ 131 it_func = (it_func_ptr)->func; \ 132 __data = (it_func_ptr)->data; \ 133 ((void(*)(proto))(it_func))(args); \ 134 } while ((++it_func_ptr)->func); \ 135 } \ 136 rcu_read_unlock_sched_notrace(); \ 137 postrcu; \ 138 } while (0) 139
#define __DECLARE_TRACE(name, proto, args, cond, data_proto, data_args) \ 168 extern struct tracepoint __tracepoint_##name; \ 169 static inline void trace_##name(proto) \ 170 { \ 171 if (static_key_false(&__tracepoint_##name.key)) \ 172 __DO_TRACE(&__tracepoint_##name, \ 173 TP_PROTO(data_proto), \ 174 TP_ARGS(data_args), \ 175 TP_CONDITION(cond),,); \ 176 if (IS_ENABLED(CONFIG_LOCKDEP) && (cond)) { \ 177 rcu_read_lock_sched_notrace(); \ 178 rcu_dereference_sched(__tracepoint_##name.funcs);\ 179 rcu_read_unlock_sched_notrace(); \ 180 } \ 181 } \ 182 __DECLARE_TRACE_RCU(name, PARAMS(proto), PARAMS(args), \ 183 PARAMS(cond), PARAMS(data_proto), PARAMS(data_args)) \ 184 static inline int \ 185 register_trace_##name(void (*probe)(data_proto), void *data) \ 186 { \ 187 return tracepoint_probe_register(&__tracepoint_##name, \ 188 (void *)probe, data); \ 189 } \ 190 static inline int \ 191 unregister_trace_##name(void (*probe)(data_proto), void *data) \ 192 { \ 193 return tracepoint_probe_unregister(&__tracepoint_##name,\ 194 (void *)probe, data); \ 195 } \ 196 static inline void \ 197 check_trace_callback_type_##name(void (*cb)(data_proto)) \ 198 { \ 199 } \ 200 static inline bool \ 201 trace_##name##_enabled(void) \ 202 { \ 203 return static_key_false(&__tracepoint_##name.key); \ 204 }
50int tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data) 251{ 252 struct tracepoint_func tp_func; 253 int ret; 254 255 mutex_lock(&tracepoints_mutex); 256 tp_func.func = probe; 257 tp_func.data = data; 258 ret = tracepoint_add_func(tp, &tp_func); 259 mutex_unlock(&tracepoints_mutex); 260 return ret; 261} 262EXPORT_SYMBOL_GPL(tracepoint_probe_register); 263
#define DEFINE_TRACE_FN(name, reg, unreg) \ 212 static const char __tpstrtab_##name[] \ 213 __attribute__((section("__tracepoints_strings"))) = #name; \ 214 struct tracepoint __tracepoint_##name \ 215 __attribute__((section("__tracepoints"))) = \ 216 { __tpstrtab_##name, STATIC_KEY_INIT_FALSE, reg, unreg, NULL };\ 217 static struct tracepoint * const __tracepoint_ptr_##name __used \ 218 __attribute__((section("__tracepoints_ptrs"))) = \ 219 &__tracepoint_##name; 220 221#define DEFINE_TRACE(name) \ 222 DEFINE_TRACE_FN(name, NULL, NULL); 223 224#define EXPORT_TRACEPOINT_SYMBOL_GPL(name) \ 225 EXPORT_SYMBOL_GPL(__tracepoint_##name) 226#define EXPORT_TRACEPOINT_SYMBOL(name) \ 227 EXPORT_SYMBOL(__tracepoint_##name) 228
arg... 用法
# define lll_debug(format, arg ...) \ LLOGD("[DEBUG] %s:%d:%s:: " format "\n", \ __FILE__, __LINE__, __func__, ## arg) #define llll_debug(arg ...) \ LLOGD(arg) #define lllll_debug(s,arg ...) \ sprintf(s,arg)
lll_debug("%s %s %d ","LIYL","TEST",1); // LIYL TEST 1 llll_debug("%s %s %d ","LIYL","TEST",1);// LIYL TEST 1 char aaaa[512] = {0,}; lllll_debug(aaaa,"%s %s %d ","LIYL","TEST",1); LLOGD("%s",aaaa);// LIYL TEST 1