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
相關文章
相關標籤/搜索