#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