C语言小知识收集

#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
相关文章
相关标签/搜索