藍海策略提供了一個清晰的4步驟流程(買方效益→價格→成本→推行),協助企業擺脫競爭對手,並且建立起一片獲利強勁成長的藍海。
這套4步驟流程是環繞著藍海策略和公平程序(fair process)的概念和分析工具所設計的,透過這套流程,經理人和他們的團隊可以在研擬嚴謹和具體的策略的同時,不至於見樹不見林、掌握大願景。
-
參考資料:
- https://www.managertoday.com.tw/articles/view/51294, 8個要點,一次讀懂藍海策略
brook@vista:/home/brook/apps_proc/poky/build$ tar zxvf tmp-glibc/deploy/images/mdm9607/machine-image-mdm9607-dbg.tar.gz ./ ./var/ ./var/lib/ ./var/lib/opkg/ ./var/lib/opkg/info/ ... brook@vista:/home/brook/apps_proc/poky/build$ mv usr/lib/.debug/* usr/lib/ brook@vista:/home/brook/apps_proc/poky/build$ mv lib/.debug/* lib brook@vista:/home/brook/apps_proc/poky/build$ ln -s libconfig.so.9.2.0 usr/lib/libconfig.so.9 ... brook@vista:/home/brook/apps_proc/poky/build$ ln -s libpthread-2.22.so lib/libpthread.so.0 brook@vista:/home/brook/apps_proc/poky/build$ ln -s librt-2.22.so lib/librt.so.1 brook@vista:/home/brook/apps_proc/poky/build$ ln -s libm-2.22.so lib/libm.so.6 brook@vista:/home/brook/apps_proc/poky/build$ ln -s libc-2.22.so lib/libc.so.6 brook@vista:/home/brook/apps_proc/poky/build$ ln -s ld-2.22.so lib/ld-linux.so.3 brook@vista:/home/brook/apps_proc/poky/build$ ln -s libdl-2.22.so lib/libdl.so.2 ... brook@vista:/home/brook/apps_proc/poky/build/tmp-glibc/work/armv7a-vfp-neon-oe-linux-gnueabi/myprog/git-r0/build/src$ adb push myprog /usr/bin/myprog brook@vista:/home/brook/apps_proc/poky/build/tmp-glibc/work/armv7a-vfp-neon-oe-linux-gnueabi/myprog/git-r0/build/src$ adb shell sh-3.2# gdbserver :2345 /usr/bin/myprog Process /usr/bin/myprog created; pid = 9035 Listening on port 2345
brook@vista:/home/brook/apps_proc/poky/build/tmp-glibc/work/armv7a-vfp-neon-oe-linux-gnueabi/myprog/git-r0/build/src$ arm-oe-linux-gnueabi-gdb myprog
GNU gdb (GDB) 7.10.1
Copyright (C) 2015 Free Software Foundation, Inc.
...
Reading symbols from myprog...done.
(gdb) set sysroot /home/brook/apps_proc/poky/build/
(gdb) target remote 10.0.0.1:2345
Remote debugging using 10.0.0.1:2345
Reading symbols from /home/brook/apps_proc/poky/build//lib/ld-linux.so.3...done.
0xb6fceac0 in ?? ()
(gdb) b main
Breakpoint 1 at 0x7f5595ac: file /home/brook/apps_proc/poky/build/tmp-glibc/work/armv7a-vfp-neon-oe-linux-gnueabi/myprog/git-r0/src/main.c, line 207.
(gdb) c
Continuing.
Breakpoint 1, main (argc=1, argv=0xbefffdf4)
at /home/brook/apps_proc/poky/build/tmp-glibc/work/armv7a-vfp-neon-oe-linux-gnueabi/myprog/git-r0/src/main.c:207
207 {
(gdb) set sysroot /home/brook/apps_proc/poky/build
warning: .dynamic section for "/home/brook/apps_proc/poky/build/lib/libpthread.so.0" is not at the expected address (wrong library or version mismatch?)
warning: .dynamic section for "/home/brook/apps_proc/poky/build/lib/libm.so.6" is not at the expected address (wrong library or version mismatch?)
warning: .dynamic section for "/home/brook/apps_proc/poky/build/lib/libc.so.6" is not at the expected address (wrong library or version mismatch?)
Use the "info sharedlibrary" command to see the complete listing.
Do you need "set solib-search-path" or "set sysroot"?
Reading symbols from /home/brook/apps_proc/poky/build/usr/lib/libconfig.so.9...done.
Reading symbols from /home/brook/apps_proc/poky/build/lib/libpthread.so.0...done.
Reading symbols from /home/brook/apps_proc/poky/build/lib/librt.so.1...done.
Reading symbols from /home/brook/apps_proc/poky/build/lib/libm.so.6...done.
Reading symbols from /home/brook/apps_proc/poky/build/lib/libc.so.6...done.
Reading symbols from /home/brook/apps_proc/poky/build/lib/libdl.so.2...done.
(gdb) info share
From To Syms Read Shared Object Library
0x7473e7c0 0x7475a328 Yes /home/brook/apps_proc/poky/build/lib/ld-linux.so.3
0xb6fc42d0 0xb6fca6e0 Yes /home/brook/apps_proc/poky/build/usr/lib/libconfig.so.9
0xb6ebc210 0xb6ecb4e8 Yes /home/brook/apps_proc/poky/build/lib/libpthread.so.0
0xb6ea2720 0xb6ea6034 Yes /home/brook/apps_proc/poky/build/lib/librt.so.1
0xb6e28bf0 0xb6e5ac20 Yes /home/brook/apps_proc/poky/build/lib/libm.so.6
0xb6ced280 0xb6dee638 Yes /home/brook/apps_proc/poky/build/lib/libc.so.6
0xb6cc3928 0xb6cc4870 Yes /home/brook/apps_proc/poky/build/lib/libdl.so.2
確認所有symbol都有找到之後, 就可以開始debug之旅了.
The most readable code is no code at all.Programmer最重要的技能之一就是知道哪些code不用寫,因為寫出來就要測試&維護,越小的程式碼越容易被維護,coupling程度越低越好,最好彼此獨立,有幾個方向:
You do not really understand something unless you can explain it to your grandmother.— Albert Einstein
We are reading three row iterators in parallel. Whenever the rows' times don't line up, advance the rows so they do line up. Then print the aligned rows, and advance the rows again. Keep doing this until there are no more matching rows left.
def PrintStockTransactions():
stock_iter = ...
price_iter = ...
num_shares_iter = ...
while True:
time = AdvanceToMatchingTime(stock_iter, price_iter, num_shares_iter)
if time is None:
return
# Print the aligned rows.
print "@", time,
print stock_iter.ticker_symbol,
print price_iter.price,
print num_shares_iter.number_of_shares
stock_iter.NextRow()
price_iter.NextRow()
num_shares_iter.NextRow()
var vote_changed = function (vote) {
var score = get_score();
score += vote_value(vote);
set_score(score);
};
// Return which element of 'array' is closest to the given latitude/longitude.
// Models the Earth as a perfect sphere.
var findClosestLocation = function (lat, lng, array) {
var closest;
var closest_dist = Number.MAX_VALUE;
for (var i = 0; i < array.length; i += 1) {
// Convert both points to radians.
var lat_rad = radians(lat);
var lng_rad = radians(lng);
var lat2_rad = radians(array[i].latitude);
var lng2_rad = radians(array[i].longitude);
// Use the "Spherical Law of Cosines" formula.
var dist = Math.acos(Math.sin(lat_rad) * Math.sin(lat2_rad) +
Math.cos(lat_rad) * Math.cos(lat2_rad) *
Math.cos(lng2_rad - lng_rad));
if (dist < closest_dist) {
closest = array[i];
closest_dist = dist;
}
}
return closest;
};
抽離後的code
var spherical_distance = function (lat1, lng1, lat2, lng2) {
var lat1_rad = radians(lat1);
var lng1_rad = radians(lng1);
var lat2_rad = radians(lat2);
var lng2_rad = radians(lng2);
// Use the "Spherical Law of Cosines" formula.
return Math.acos(Math.sin(lat1_rad) * Math.sin(lat2_rad) +
Math.cos(lat1_rad) * Math.cos(lat2_rad) *
};
var findClosestLocation = function (lat, lng, array) {
var closest;
var closest_dist = Number.MAX_VALUE;
for (var i = 0; i < array.length; i += 1) {
var dist = spherical_distance(lat, lng, array[i].latitude, array[i].longitude);
if (dist < closest_dist) {
closest = array[i];
closest_dist = dist;
}
}
return closest;
};
抽離這些子問題的另一個好處容易優化,比如有更好的方式去運算spherical_distance()或是變更findClosestLocation()的運算邏輯。建立通用的function也是一個很好也很重要的習慣,當你開發一個新的program時,就可以運用這些通用function,快速建立一個prototype。
DT在Linux底下有三個主要目的 1) platform identification, 2) runtime configuration, and 3) device population.
compatible = "ti,omap3-beagleboard-xm", "ti,omap3450", "ti,omap3";
上面的例子定義了"ti,omap3-beagleboard-xm",也宣稱相容"OMAP 3450 SOC"與"OMAP3"系列的SoC,你會注意到這樣的宣稱會從最具體的board到SoC的家族,關於compatible的值必須進行記錄說明其含義。
i2c_add_driver( ) @ i2c.h
|-> i2c_register_driver() @i2c-core.c /* 將device_driver中的bus_type設成i2c_bus_type */
|--> driver_register() @driver.c
|--> bus_add_driver() @bus.c /* 建立sysfs file node 與 attr */
|--> driver_attach() @dd.c
|--> bus_for_each_dev(drv->bus, NULL, drv, __driver_attach) @bus.c
|--> __driver_attach @dd.c
|--> driver_match_device(drv, dev) @base.h
|--> i2c_device_match() @i2c-core.c
/***********************************************
如果是device tree, 會透過 of_driver_match_device()去做匹配的動作
如果不是device tree就改用 i2c_match_id()去完成匹配的動作
***************************************************/
/* Attempt an OF style match */
if (of_driver_match_device(dev, drv))
return 1;
/* Then ACPI style match */
if (acpi_driver_match_device(dev, drv))
return 1;
driver = to_i2c_driver(drv);
/* match on an id table if there is one */
if (driver->id_table)
return i2c_match_id(driver->id_table, client) != NULL;
|--> driver_probe_device() @dd.c
/*如果匹配成功, 接下來就要準備 call driver 中的 probe function*/
|--> really_probe() @dd.c
|--> i2c_device_probe() @i2c-core.c
|--> rt5627_i2c_probe() @rt5627.c
from http://janbarry0914.blogspot.com/2014/08/device-tree-i2c-device-driver-match.html
#ifndef SM_H #define SM_H struct sm { int cur_state; int prv_event; void *v; }; /** * state function * @return next state */ typedef int (*sm_st_fp)(struct sm *sm, int new_event); struct sm *sm_alloc(int num_of_state); int sm_run(struct sm *s, int new_event); int sm_fp_reg(struct sm *s, int state, sm_st_fp fp); #endif
#include <stdio.h> #include <stdlib.h> #include <string.h> #include "sm.h" struct _sm { struct sm s; int num_of_st; sm_st_fp fp[0]; }; struct sm *sm_alloc(int num_of_state) { struct _sm *_s; int sz; sz = sizeof(struct _sm) + sizeof(sm_st_fp) * num_of_state; _s = (struct _sm*) malloc(sz); if (!_s) { return NULL; } memset(_s, 0, sz); _s->num_of_st = num_of_state; return (struct sm*)_s; } int sm_run(struct sm *s, int new_event) { struct _sm *_s = (struct _sm*) s; if (s->cur_state > _s->num_of_st) { printf("out of st\n"); return -1; } if (!_s->fp[s->cur_state]) { printf("null fp\n"); return -1; } s->cur_state = _s->fp[s->cur_state](s, new_event); s->prv_event = new_event; return 0; } int sm_fp_reg(struct sm *s, int state, sm_st_fp fp) { struct _sm *_s = (struct _sm*) s; if (state > _s->num_of_st) { printf("out of st\n"); return -1; } _s->fp[state] = fp; return 0; }
因為是framework,所以,我把state/event都拉出來, 因此每個State Machine都應該定義自己的event與state。 enum state { STATE_1, STATE_2, STATE_3, STATE_4, }; enum event { E1 = 1, E2, E3, E4, }; int main(int argc, char *argv[]) { struct sm *s; char ch; s = sm_alloc(3); if (!s) { return -1; } sm_fp_reg(s, STATE_1, in_state_1); sm_fp_reg(s, STATE_2, in_state_2); sm_fp_reg(s, STATE_3, in_state_3); sm_fp_reg(s, STATE_4, in_state_4); while (1) { while (((ch = getc(stdin)) == '\n') || (ch < '0') || (ch > '4')); sm_run(s, ch - '0'); } return 0; }
因為是framework,所以,callback function的定義要改成return int。 int do_s1(void) { printf("%s(#%d)\n", __FUNCTION__, __LINE__); return STATE_1; } int do_s2(void) { printf("%s(#%d)\n", __FUNCTION__, __LINE__); return STATE_2; } int do_s3(void) { printf("%s(#%d)\n", __FUNCTION__, __LINE__); return STATE_3; } int do_s4(void) { printf("%s(#%d)\n", __FUNCTION__, __LINE__); return STATE_4; } int in_state_1(struct sm *s, int new_event) { printf("%s(#%d): pre_evt:%d, new_evt:%d\n", __FUNCTION__, __LINE__, s->prv_event, new_event); switch (new_event) { case E1: printf("change to S2\n"); return do_s2(); case E2: printf("change to S3\n"); return do_s3(); default: printf("keep the same STATE && do nothing\n"); return STATE_1; } } int in_state_2(struct sm *s, int new_event) { printf("%s(#%d): pre_evt:%d, new_evt:%d\n", __FUNCTION__, __LINE__, s->prv_event, new_event); switch (new_event) { case E3: printf("change to S3\n"); return do_s3(); default: printf("keep the same STATE && do s2 again\n"); return do_s2(); // do s2 again } } int in_state_3(struct sm *s, int new_event) { printf("%s(#%d): pre_evt:%d, new_evt:%d\n", __FUNCTION__, __LINE__, s->prv_event, new_event); switch (new_event) { case E2: printf("change to S4\n"); return do_s4(); default: printf("keep the same STATE && do nothing\n"); return STATE_3; } } int in_state_4(struct sm *s, int new_event) { printf("%s(#%d): pre_evt:%d, new_evt:%d\n", __FUNCTION__, __LINE__, s->prv_event, new_event); switch (new_event) { case E1: printf("change to S2\n"); return do_s2(); case E3: printf("change to S1\n"); return do_s1(); default: printf("keep the same STATE && do again\n"); return do_s4(); } }
root_message.last_view_time = datetime.datetime.now() 會比下面code更容易理解 now = datetime.datetime.now() root_message.last_view_time = now
boolean done = false;
while (/* condition */ && !done) {
...
if (...) {
done = true;
continue;
}
}
與
var remove_one = function (array, value_to_remove) {
var index_to_remove = null;
for (var i = 0; i < array.length; i += 1) {
if (array[i] === value_to_remove) {
index_to_remove = i;
break;
}
}
if (index_to_remove !== null) {
array.splice(index_to_remove, 1);
}
};
submitted = false; // Note: global variable
var submit_form = function (form_name) {
if (submitted) {
return; // don't double-submit the form
}
...
submitted = true;
};
可以被修改成
var submit_form = (function () {
var submitted = false; // Note: can only be accessed by the function below
return function (form_name) {
if (submitted) {
return; // don't double-submit the form
}
...
submitted = true;
};
}());
#ifndef NOTIFICATION_CHAIN_H #define NOTIFICATION_CHAIN_H enum notif_id { /* 新的ID請加在這裡 */ notif_id_network, notif_id_lte, notif_id_max /* must be last */ }; int notif_init(void); typedef int (*notif_call_fp)(char const * caller, unsigned long val, void *v); int _notif_reg(enum notif_id nid, notif_call_fp notif_call, char *notif_call_name, int priority); #define notif_reg(nid, notif_call, priority) _notif_reg(nid, notif_call, #notif_call, priority); int notif_unreg(enum notif_id nid, notif_call_fp notif_call); char * notif_dump(char *buf, int sz); /* call in the caller thread */ int _blocking_notif_call(enum notif_id nid, unsigned long val, /* Value passed to notifier function */ void *v, /* Pointer passed to notifier function */ char const * caller); #define blocking_notif_call(nid, val, v) _blocking_notif_call(nid, val, v, __FUNCTION__) /* call by another thread */ int async_notif_call(enum notif_id nid, unsigned long val /* Value passed to notifier function */, void *v /* Pointer passed to notifier function */, void (*free_v)(void *v)); #endif
#include <pthread.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <ctype.h> #include <time.h> #include <sys/time.h> #include <sys/timerfd.h> #include <stdint.h> #include <unistd.h> #include <pthread.h> #include "notification-chain.h" struct notif_block { notif_call_fp notif_call; char *notif_call_name; struct notif_block *next; int priority; int called; }; struct notif_chain_head { pthread_mutex_t mutex; pthread_cond_t cond; struct notif_block *next; }; struct notif_statistical { unsigned int alloc; unsigned int alloced; unsigned int freed; }; struct notif_statistical notif_statistical = {}; static struct notif_chain_head *_notif_chain_tab = NULL; static int _init_notif_chain(struct notif_chain_head **h) { int i; *h = (struct notif_chain_head *) malloc(sizeof(struct notif_chain_head) * notif_id_max); if (!*h) { return -1; } for (i = 0; i < notif_id_max; i++) { pthread_mutex_init(&((*h)[i].mutex), NULL); pthread_cond_init(&((*h)[i].cond), NULL); (*h)[i].next = NULL; } return 0; } int notif_init(void) { int ret = 0; if ((ret = _init_notif_chain(&_notif_chain_tab)) < 0) { return ret; } return ret; } static int _notif_check_parms(enum notif_id nid, notif_call_fp notif_call, char *notif_call_name) { if (!_notif_chain_tab) { return -1; } if ((nid < 0) || (nid >= notif_id_max)) { return -1; } if (!notif_call) { return -1; } if (!notif_call_name) { return -1; } return 0; } static int _notif_block_alloc(struct notif_block **n) { notif_statistical.alloc++; *n = (struct notif_block*) malloc(sizeof(struct notif_block)); if (!(*n)) { return -1; } memset(*n, 0, sizeof(struct notif_block)); notif_statistical.alloced++; return 0; } static int _notif_block_free(struct notif_block *n) { notif_statistical.freed++; if (n->notif_call_name) { free(n->notif_call_name); } if (n) { free(n); } return 0; } int _notif_reg(enum notif_id nid, notif_call_fp notif_call, char *notif_call_name, int priority) { struct notif_block **n, *nb; if (_notif_check_parms(nid, notif_call, notif_call_name) < 0) { return -1; } if (_notif_block_alloc(&nb) < 0) { return -1; } /* fill info */ nb->notif_call = notif_call; nb->notif_call_name = strdup(notif_call_name); if (!nb->notif_call_name) { _notif_block_free(nb); return -1; } nb->priority = priority; /* insert into tab */ pthread_mutex_lock(&(_notif_chain_tab[nid].mutex)); n = &(_notif_chain_tab[nid].next); while ((*n) && ((*n)->priority > nb->priority)) { n = &((*n)->next); } nb->next = *n; *n = nb; pthread_mutex_unlock(&(_notif_chain_tab[nid].mutex)); return 0; } int notif_unreg(enum notif_id nid, notif_call_fp notif_call) { struct notif_block **n, *sn = NULL; if (_notif_check_parms(nid, notif_call, (void *) 0xFF /* ignore check */) < 0) { return -1; } pthread_mutex_lock(&(_notif_chain_tab[nid].mutex)); n = &(_notif_chain_tab[nid].next); while ((*n)) { if ((*n)->notif_call == notif_call) { sn = *n; *n = (*n)->next; break; } n = &((*n)->next); } pthread_mutex_unlock(&(_notif_chain_tab[nid].mutex)); if (!sn) { // not found return -1; } _notif_block_free(sn); return 0; } /* call in the caller thread */ int _blocking_notif_call(enum notif_id nid, unsigned long val, /* Value passed to notifier function */ void *v, /* Pointer passed to notifier function */ char const * caller) { struct notif_block *n; if (_notif_check_parms(nid, (void*) 0xFF /* just ignore check */, (void *) 0xFF /* just ignore check */) < 0) { return -1; } /* insert into tab */ pthread_mutex_lock(&(_notif_chain_tab[nid].mutex)); n = _notif_chain_tab[nid].next; while (n) { n->notif_call(caller, val, v); n->called++; n = n->next; } pthread_mutex_unlock(&(_notif_chain_tab[nid].mutex)); return 0; } char * notif_dump(char *buf, int sz) { int i; char *p = buf; struct notif_block *n; memset(buf, 0, sz); p += snprintf(p, sz - (buf - p), "\tnotif_fp/notif_fp_name/pri called\n"); for (i = 0; i < notif_id_max; i++) { pthread_mutex_lock(&(_notif_chain_tab[i].mutex)); n = _notif_chain_tab[i].next; p += snprintf(p, sz - (buf - p), "notif id: %d\n", i); while (n) { p += snprintf(p, sz - (buf - p), "\t%p/%s/%d %d\n", n->notif_call, n->notif_call_name, n->priority, n->called); n = n->next; } pthread_mutex_unlock(&(_notif_chain_tab[i].mutex)); } return buf; }
#include <stdio.h> #include <unistd.h> #include "notification-chain.h" /* 這裡有用service-reg作為publisher */ #include "service-reg.h" #define LINK_DOWN 0 #define LINK_UP 1 void *publisher(void *v) { int *link_state = (int *) v; ++(*link_state); (*link_state) %= 2; blocking_notif_call(notif_id_network, *link_state, NULL); } int link_notif_call1(char const *caller, unsigned long val, void *v) { printf("%s(#%d): caller:%s, %s\n", __FUNCTION__, __LINE__, caller, val == LINK_UP ? "UP" : "DOWN"); return 0; } int link_notif_call2(char const *caller, unsigned long val, void *v) { printf("%s(#%d): caller:%s, %s\n", __FUNCTION__, __LINE__, caller, val == LINK_UP ? "UP" : "DOWN"); return 0; } int link_notif_call3(char const *caller, unsigned long val, void *v) { printf("%s(#%d): caller:%s, %s\n", __FUNCTION__, __LINE__, caller, val == LINK_UP ? "UP" : "DOWN"); return 0; } int main(int argc, char *argv[]) { int link_state = 0; char buf[1024]; /* 請先call notif_init()做初始化 */ notif_init(); srv_reg("publisher", publisher, &link_state); srv_start_periodical("publisher", 1, 0); sleep(2); printf("reg 1, 10\n"); notif_reg(notif_id_network, link_notif_call1, 10); sleep(2); printf("dump\n"); printf("%s\n", notif_dump(buf, sizeof(buf))); sleep(2); printf("reg 3, 30\n"); notif_reg(notif_id_network, link_notif_call3, 30); sleep(2); printf("reg 2, 20\n"); notif_reg(notif_id_network, link_notif_call2, 20); sleep(2); printf("dump\n"); printf("%s\n", notif_dump(buf, sizeof(buf))); sleep(2); printf("unreg 3\n"); notif_unreg(notif_id_network, link_notif_call3); sleep(2); printf("dump\n"); printf("%s\n", notif_dump(buf, sizeof(buf))); sleep(2); printf("unreg 1 lte \n"); notif_unreg(notif_id_lte, link_notif_call1); sleep(2); printf("dump\n"); printf("%s\n", notif_dump(buf, sizeof(buf))); return 0; }
brook@vista:~/notification-chain$ ./demo
reg 1, 10
link_notif_call1(#20): caller:publisher, UP
link_notif_call1(#20): caller:publisher, DOWN
dump
notif_fp/notif_fp_name/pri called
notif id: 0
0x400fa4/link_notif_call1/10 2
notif id: 1
link_notif_call1(#20): caller:publisher, UP
link_notif_call1(#20): caller:publisher, DOWN
reg 3, 30
link_notif_call3(#34): caller:publisher, UP
link_notif_call1(#20): caller:publisher, UP
link_notif_call3(#34): caller:publisher, DOWN
link_notif_call1(#20): caller:publisher, DOWN
reg 2, 20
link_notif_call3(#34): caller:publisher, UP
link_notif_call2(#27): caller:publisher, UP
link_notif_call1(#20): caller:publisher, UP
link_notif_call3(#34): caller:publisher, DOWN
link_notif_call2(#27): caller:publisher, DOWN
link_notif_call1(#20): caller:publisher, DOWN
dump
notif_fp/notif_fp_name/pri called
notif id: 0
0x401046/link_notif_call3/30 4
0x400ff5/link_notif_call2/20 2
0x400fa4/link_notif_call1/10 8
notif id: 1
link_notif_call3(#34): caller:publisher, UP
link_notif_call2(#27): caller:publisher, UP
link_notif_call1(#20): caller:publisher, UP
link_notif_call3(#34): caller:publisher, DOWN
link_notif_call2(#27): caller:publisher, DOWN
link_notif_call1(#20): caller:publisher, DOWN
unreg 3
link_notif_call2(#27): caller:publisher, UP
link_notif_call1(#20): caller:publisher, UP
link_notif_call2(#27): caller:publisher, DOWN
link_notif_call1(#20): caller:publisher, DOWN
dump
notif_fp/notif_fp_name/pri called
notif id: 0
0x400ff5/link_notif_call2/20 6
0x400fa4/link_notif_call1/10 12
notif id: 1
link_notif_call2(#27): caller:publisher, UP
link_notif_call1(#20): caller:publisher, UP
link_notif_call2(#27): caller:publisher, DOWN
link_notif_call1(#20): caller:publisher, DOWN
unreg 1 lte
link_notif_call2(#27): caller:publisher, UP
link_notif_call1(#20): caller:publisher, UP
link_notif_call2(#27): caller:publisher, DOWN
link_notif_call1(#20): caller:publisher, DOWN
dump
notif_fp/notif_fp_name/pri called
notif id: 0
0x400ff5/link_notif_call2/20 10
0x400fa4/link_notif_call1/10 16
notif id: 1
username = line.split(':')[0].strip() if username == "root":
會比下面這行容易理解
if line.split(':')[0].strip() == "root":
上面的username就被稱為"explaining variable"
final boolean user_owns_document = (request.user.id == document.owner_id);
if (user_owns_document) {
// user can edit this document...
}
這裡的user_owns_document就被稱為Summary Variables, 當然你也可以不斷的使用(request.user.id == document.owner_id)
if (!file_exists || is_protected) Error("Sorry, could not read file.");
會比下面這行容易理解
if (!(file_exists && !is_protected)) Error("Sorry, could not read file.");
// Check if 'begin' or 'end' falls inside 'other'.
bool Range::OverlapsWith(Range other) {
return (begin >= other.begin && begin lt; other.end) ||
(end > other.begin && end lt;= other.end)
}
換個方式寫會更好閱讀
bool Range::OverlapsWith(Range other) {
if (other.end <= begin) return false; // They end before we begin
if (other.begin >= end) return false; // They begin after we end
return true; // Only possibility left: they overlap
}
void AddStats(const Stats& add_from, Stats* add_to) {
#define ADD_FIELD(field) add_to->set_##field(add_from.field() + add_to->field())
ADD_FIELD(total_memory);
ADD_FIELD(free_memory);
ADD_FIELD(swap_memory);
ADD_FIELD(status_string);
ADD_FIELD(num_processes);
...
#undef ADD_FIELD
}
比下面這例子容易閱讀
void AddStats(const Stats& add_from, Stats* add_to) {
add_to->set_total_memory(add_from.total_memory() + add_to->total_memory());
add_to->set_free_memory(add_from.free_memory() + add_to->free_memory());
add_to->set_swap_memory(add_from.swap_memory() + add_to->swap_memory());
add_to->set_status_string(add_from.status_string() + add_to->status_string());
add_to->set_num_processes(add_from.num_processes() + add_to->num_processes());
...
}
#ifndef SERVICE_REG_H #define SERVICE_REG_H #include <sys/time.h> typedef void *(*srv_fp) (void *); char * srv_dump(char *buf, int sz); int _srv_reg(char *srv_name, srv_fp fp, char *fp_name, void *srv_data); #define srv_reg(srv_name, fp, srv_data) _srv_reg(srv_name, fp, #fp, srv_data) int srv_start(char *srv_name); // run forever without any delay int srv_stop(char *srv_name); int srv_unreg(char *srv_name); int srv_start_periodical(char *srv_name, unsigned long sec, unsigned long nsec); // run forever with delay #define SRV_NO_MEM -1 #endif
#include <pthread.h> #include <string.h> #include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <errno.h> #include <ctype.h> #include <time.h> #include <sys/time.h> #include <sys/timerfd.h> #include <stdint.h> #include <unistd.h> #include "service-reg.h" #include "lookup_table.h" #define SEC2NSEC 1000000000.0 struct srv_info { void *srv_data; char *srv_name; srv_fp fp; int in_fp; char *fp_name; unsigned run_cnt; pthread_t thread_id; /* ID returned by pthread_create() */ pthread_cond_t cond; pthread_mutex_t mutex; struct srv_info *next; volatile int running; /* 1 for running, 0 for stop */ struct timespec active_time; struct timespec last_enter; struct timespec last_exit; int tm_fd; /* used to delay */ }; struct srv_tab { pthread_mutex_t mutex; struct srv_info *list; unsigned int num_srv; } srv_tab = { .mutex = PTHREAD_MUTEX_INITIALIZER, .list = NULL, .num_srv = 0, }; static void _srv_update_active_time(struct srv_info *s) { clock_gettime(CLOCK_MONOTONIC, &(s->last_exit)); s->active_time.tv_sec += s->last_exit.tv_sec - s->last_enter.tv_sec; if (s->last_exit.tv_nsec > s->last_enter.tv_nsec) { s->active_time.tv_nsec += s->last_exit.tv_nsec - s->last_enter.tv_nsec; } else { s->active_time.tv_sec--; s->active_time.tv_nsec += SEC2NSEC + s->last_exit.tv_nsec - s->last_enter.tv_nsec; } if (s->active_time.tv_nsec >= SEC2NSEC) { s->active_time.tv_nsec -= SEC2NSEC; s->active_time.tv_sec++; } } static void *_srv_wrap(void *v) { struct srv_info *s = (struct srv_info *) v; while (1) { recheck: if (s->running == 0) { stoprun: pthread_cond_wait(&(s->cond), &(s->mutex)); goto recheck; } /* if timer is enabled, than wait */ again: if (s->tm_fd != -1) { uint64_t exp; ssize_t sz; sz = read(s->tm_fd, &exp, sizeof(exp)); if (sz != sizeof(exp)) { printf("timerfd_settime failed: s->tm_fd:%d, errno:%d/%s\n", s->tm_fd, errno, strerror(errno)); if (errno == EINTR) { goto again; } } if (s->running == 0) { goto stoprun; } } clock_gettime(CLOCK_MONOTONIC, &(s->last_enter)); s->in_fp = 1; s->fp(s->srv_data); s->in_fp = 0; _srv_update_active_time(s); s->run_cnt++; } return NULL; } int srv_init(void) { return 0; } char * srv_dump(char *buf, int sz) { struct srv_info *s; char *p = buf; int i = 0; struct timespec cur_clk; struct itimerspec cur_timer; clock_gettime(CLOCK_MONOTONIC, &cur_clk); if (buf == NULL) { return NULL; } memset(buf, 0, sz); pthread_mutex_lock(&(srv_tab.mutex)); s = srv_tab.list; p += snprintf(p, sz - (buf - p), "cur-clk: %f\n", cur_clk.tv_sec + cur_clk.tv_nsec/SEC2NSEC); p += snprintf(p, sz - (buf - p), "id srv_name running/in_fp\t\tfp/fname/dp\n"); p += snprintf(p, sz - (buf - p), "\t\t\trun-cnt/run-time\tenter-clk/leave-clk\n"); p += snprintf(p, sz - (buf - p), "\t\t\ttm_fd/next_expir/perodic\n"); while (s != NULL) { p += snprintf(p, sz - (buf - p), "%-8d%-16s%2d/%-2d\t\t%16p/%s/%-16p\t\t\t\n", i++, s->srv_name, s->running, s->in_fp, s->fp, s->fp_name, s->srv_data); p += snprintf(p, sz - (buf - p), "\t\t %10d/%-12f\t%12f/%-12f\n", s->run_cnt, s->active_time.tv_sec + s->active_time.tv_nsec/SEC2NSEC, s->last_enter.tv_sec + s->last_enter.tv_nsec/SEC2NSEC, s->last_exit.tv_sec + s->last_exit.tv_nsec/SEC2NSEC); if (s->tm_fd != -1) { if (timerfd_gettime(s->tm_fd, &cur_timer) < 0) { printf("timerfd_get failed: errno:%d/%s\n", errno, strerror(errno)); p += snprintf(p, sz - (buf - p), "\t\t %6d\n", s->tm_fd); } else { p += snprintf(p, sz - (buf - p), "\t\t %6d/%f/%-16f\n", s->tm_fd, cur_timer.it_value.tv_sec + cur_timer.it_value.tv_nsec/SEC2NSEC, cur_timer.it_interval.tv_sec + cur_timer.it_interval.tv_nsec/SEC2NSEC); } } s = s->next; } pthread_mutex_unlock(&(srv_tab.mutex)); return buf; } int _srv_reg(char *srv_name, srv_fp fp, char *fp_name, void *srv_data) { struct srv_info *s = (struct srv_info *) malloc(sizeof(struct srv_info)); if (s == NULL) { return SRV_NO_MEM; } memset(s, 0, sizeof(struct srv_info)); s->fp = fp; s->srv_data = srv_data; s->srv_name = strdup(srv_name); s->fp_name = strdup(fp_name); pthread_cond_init(&s->cond, NULL); pthread_mutex_init(&s->mutex, NULL); s->tm_fd = -1; if (!s->srv_name) { free(s); return SRV_NO_MEM; } /* insert into tab */ pthread_mutex_lock(&(srv_tab.mutex)); s->next = srv_tab.list; srv_tab.list = s; srv_tab.num_srv++; pthread_mutex_unlock(&(srv_tab.mutex)); /* create the thread */ pthread_create(&s->thread_id, NULL , _srv_wrap, s); return 0; } static int _srv_update_timer(struct srv_info *s, unsigned long sec, unsigned long nsec) { struct timespec now_tm; struct itimerspec new_tm; if (s->tm_fd < 0) { s->tm_fd = timerfd_create(CLOCK_MONOTONIC, 0); if (s->tm_fd < 0) { printf("timerfd_create failed: errno:%d/%s\n", errno, strerror(errno)); return -1; } } if (clock_gettime(CLOCK_MONOTONIC, &now_tm) == -1) { printf("timerfd_create failed: errno:%d/%s\n", errno, strerror(errno)); return -1; } new_tm.it_value.tv_sec = now_tm.tv_sec + sec; new_tm.it_value.tv_nsec = now_tm.tv_nsec + nsec; new_tm.it_interval.tv_sec = sec; new_tm.it_interval.tv_nsec = nsec; if (timerfd_settime(s->tm_fd, TFD_TIMER_ABSTIME, &new_tm, NULL) < 0) { printf("timerfd_settime failed: errno:%d/%s\n", errno, strerror(errno)); return -1; } return 0; } inline static int _srv_name_equal(struct srv_info *s, char *srv_name) { return strlen(s->srv_name) == strlen(srv_name) && !strcmp(s->srv_name, srv_name); } static int _srv_set_running(char *srv_name, int running, unsigned long sec, unsigned long nsec) { struct srv_info *s; int ret = 0; pthread_mutex_lock(&(srv_tab.mutex)); s = srv_tab.list; while (s != NULL) { if (_srv_name_equal(s, srv_name)) { s->running = running; if (sec || nsec) { ret = _srv_update_timer(s, sec, nsec); } else { /* reset timer to zero */ _srv_update_timer(s, 0, 0); /* clear timer */ close(s->tm_fd); s->tm_fd = -1; } pthread_cond_signal(&s->cond); pthread_mutex_unlock(&(srv_tab.mutex)); return ret; } s = s->next; } pthread_mutex_unlock(&(srv_tab.mutex)); return -1; } int srv_start(char *srv_name) { return _srv_set_running(srv_name, 1 /* running */, 0 /* delay.sec */, 0 /* delay.nsec */); } int srv_stop(char *srv_name) { return _srv_set_running(srv_name, 0 /* running */, 0 /* delay.sec */, 0 /* delay.nsec */); } static int _srv_free(struct srv_info *s) { int ret; s->running = 0; /* cancel the thread */ ret = pthread_cancel(s->thread_id); if (ret != 0) { printf("pthread_cancel failed: %d/%d\n", ret, errno); /* FIXME */ } ret = pthread_join(s->thread_id, NULL); if (ret != 0) { printf("pthread_join failed: %d/%d\n", ret, errno); /* FIXME */ } /* free resouce */ pthread_cond_destroy(&(s->cond)); pthread_mutex_destroy(&(s->mutex)); free(s->srv_name); free(s->fp_name); if (s->tm_fd != -1) { close(s->tm_fd); } free(s); return ret; } int srv_unreg(char *srv_name) { struct srv_info **s, *sn = NULL; int ret; s = &(srv_tab.list); pthread_mutex_lock(&(srv_tab.mutex)); while ((*s) != NULL) { if (_srv_name_equal(*s, srv_name)) { sn = *s; *s = (*s)->next; srv_tab.num_srv--; break; } s = &((*s)->next); } pthread_mutex_unlock(&(srv_tab.mutex)); if (sn) { ret = _srv_free(sn); } return 0; } int srv_start_periodical(char *srv_name, unsigned long sec, unsigned long nsec) { return _srv_set_running(srv_name, 1 /* running */, sec /* delay.sec */, nsec /* delay.nsec */); }
#include <stdio.h> #include <stdlib.h> #include <unistd.h> #include <time.h> #include <stdarg.h> #include "service-reg.h" int pr(const char *fmt, ...) { va_list ap; int ret; struct timespec cur_clk; clock_gettime(CLOCK_MONOTONIC, &cur_clk); printf("***CLK: %f\n", cur_clk.tv_sec + cur_clk.tv_nsec/1000000000.0); va_start(ap, fmt); ret = vprintf(fmt, ap); va_end(ap); return ret; } void *sms_service(void *v) { int *i = (int *) v; pr(" ->hello, %p/%d, srv_start_periodical %d\n", v, (*i)++, 2); pr(" ->%d\n", srv_start_periodical("brook", 2, 0)); } int main(int argc, char *argv[]) { int i = 0, data = 0, ret; char name[] = "brook", buf[1024]; pr("srv_reg %s\n", name); srv_reg(name, sms_service, (void*)&data); pr("srv_start %s\n", name); srv_start(name); pr("sleep 3\n"); sleep(3); sleep(3); pr("srv_stop %s\n", name); srv_stop(name); pr("srv_start_periodical %s with %dsec\n", name, 1); srv_start_periodical(name, 1, 0); pr("srv_dump %s\n", name); pr("%s\n", srv_dump(buf, sizeof(buf))); pr("sleep 2\n"); sleep(2); pr("srv_unreg %s\n", name); srv_unreg(name); pr("over\n"); return 0; }
brook@vista:~$ ./service-reg
***CLK: 7914669.498393
srv_reg brook
***CLK: 7914669.498469
srv_start brook
***CLK: 7914669.498481
sleep 3
***CLK: 7914669.498531
->hello, 0x7ffc24e80df8/0, srv_start_periodical 2
***CLK: 7914669.498541
->0
***CLK: 7914671.498595
->hello, 0x7ffc24e80df8/1, srv_start_periodical 2
***CLK: 7914671.498647
->0
***CLK: 7914672.498576
srv_stop brook
***CLK: 7914672.498599
srv_start_periodical brook with 1sec
***CLK: 7914672.498606
srv_dump brook
***CLK: 7914672.498621
->hello, 0x7ffc24e80df8/2, srv_start_periodical 2
***CLK: 7914672.498662
->0
***CLK: 7914672.498625
cur-clk: 7914672.498611
id srv_name running/in_fp fp/fname/dp
run-cnt/run-time enter-clk/leave-clk
tm_fd/next_expir/perodic
0 brook 1/0 0x40106f/sms_service/0x7ffc24e80df8
2/0.000082 7914671.498594/7914671.498656
3/0.999982/1.000000
***CLK: 7914672.498680
sleep 2
***CLK: 7914674.498698
->hello, 0x7ffc24e80df8/3, srv_start_periodical 2
***CLK: 7914674.498730
->0
***CLK: 7914674.498742
srv_unreg brook
***CLK: 7914674.498997
over
#ifndef _LOG_H_
#define _LOG_H_
#include <syslog.h>
#include <unistd.h>
#include <sys/syscall.h>
/*************************************************
* TYPE
*************************************************/
enum log_type {
/* 這裡我先設定有三個類別,分別為AT,CORE與DB,之後請自行新增刪減修改 */
LOG_TYPE_AT,
LOG_TYPE_CORE,
LOG_TYPE_DB,
LOG_TYPE_MAX
};
#define LOG_TYPE_BIT(t) (1 << (LOG_TYPE_##t))
/***** internal function for MACRO used *****/
void _log_type_toggle(enum log_type type);
void _log_type_clr(enum log_type type);
void _log_type_set(enum log_type type);
/***** public function to enable/disable log on certain type *****/
#define log_type_toggle(type) _log_type_toggle(LOG_TYPE_##type)
#define log_type_clr(type) _log_type_clr(LOG_TYPE_##type)
#define log_type_set(type) _log_type_set(LOG_TYPE_##type)
char *get_log_type_status(void);
/*************************************************
* Format
*************************************************/
enum log_fmt {
LOG_FMT_FUNC_AND_LINE,
LOG_FMT_TID, ///<thread ID.
LOG_FMT_LOG_TYPE,
LOG_FMT_LOG_LEVEL,
LOG_FMT_MAX,
};
/***** internal function for MACRO used *****/
void _log_fmt_toggle(enum log_fmt fmt);
void _log_fmt_set(enum log_fmt fmt);
void _log_fmt_clr(enum log_fmt fmt);
int _log_fmt_is_set(enum log_fmt fmt);
/***** public function to enable/disable certain format type *****/
#define log_fmt_toggle(fmt) _log_fmt_toggle(LOG_FMT_##fmt)
#define log_fmt_set(fmt) _log_fmt_set(LOG_FMT_##fmt)
#define log_fmt_clr(fmt) _log_fmt_clr(LOG_FMT_##fmt)
#define log_fmt_is_set(fmt) _log_fmt_is_set(LOG_FMT_##fmt)
/*************************************************
* Level
*************************************************/
/***** internal function for MACRO used *****/
int _log_type_level_is(enum log_type type, int *level);
int _log_type_level_set(enum log_type type, int level);
/***** public function to set debug level. the level is leveraged from syslog *****/
#define log_type_level_is(type, level) _log_type_level_is(LOG_TYPE_##type, level)
#define log_type_level_set(type, level) _log_type_level_set(LOG_TYPE_##type, LOG_##level)
void log_pr(int type, int level, char const *const fmt,...);
const char *log_type_str(int type);
#define _log_pr(type, level, fmt, ...) \
do { \
unsigned char func[36] = {}, tid[16] = {}, tp[16] = {}, lv[16] = {};\
if (log_fmt_is_set(FUNC_AND_LINE)) { \
snprintf(func, sizeof(func) - 1, "%s(#%d), ", __FUNCTION__, __LINE__); \
} \
\
if (log_fmt_is_set(TID)) { \
snprintf(tid, sizeof(tid) - 1, "TID:%ld, ", getpid()); \
} \
\
if (log_fmt_is_set(LOG_TYPE)) { \
snprintf(tp, sizeof(tp) - 1, "%s, ", log_type_str(type)); \
} \
if (log_fmt_is_set(LOG_LEVEL)) { \
snprintf(tp, sizeof(lv) - 1, "%s, ", #level); \
} \
log_pr(type, LOG_##level, "%s%s%s%s"fmt, func, tid, tp, lv, ##__VA_ARGS__); \
} while(0)
/***** public function *****/
/* 請呼叫下面MACRO來印log */
#define pr_emerg(type, fmt, ...) _log_pr(type, EMERG, fmt, ##__VA_ARGS__)
#define pr_alert(type, fmt, ...) _log_pr(type, ALERT, fmt, ##__VA_ARGS__)
#define pr_crit(type, fmt, ...) _log_pr(type, CRIT, fmt, ##__VA_ARGS__)
#define pr_err(type, fmt, ...) _log_pr(type, ERR, fmt, ##__VA_ARGS__)
#define pr_warn(type, fmt, ...) _log_pr(type, WARNING, fmt, ##__VA_ARGS__)
#define pr_notice(type, fmt, ...) _log_pr(type, NOTICE, fmt, ##__VA_ARGS__)
#define pr_info(type, fmt, ...) _log_pr(type, INFO, fmt, ##__VA_ARGS__)
#define pr_dbg(type, fmt, ...) _log_pr(type, DEBUG, fmt, ##__VA_ARGS__)
#endif
#include <stdio.h>
#include <stdarg.h>
#include <syslog.h>
#include "brook-log.h"
#define DEFAULT_LOG_TYPE ((1 << LOG_TYPE_AT) | \
(1 << LOG_TYPE_CORE) | \
(1 << LOG_TYPE_DB))
#define DEFAULT_LOG_FMT ((1 << LOG_FMT_FUNC_AND_LINE) | \
(1 << LOG_FMT_TID) | \
(1 << LOG_FMT_LOG_TYPE))
static unsigned int _log_types = DEFAULT_LOG_TYPE;
static unsigned int _log_fmts = DEFAULT_LOG_FMT;
#define DEFAULT_LOG_OPTION (LOG_CONS | LOG_NDELAY)
#define DEFAULT_LOG_FACILITY LOG_LOCAL0
#define DEFAULT_LOG_LEVEL LOG_INFO
char const *const level_str[] = {
[LOG_EMERG] = "EMERG",
[LOG_ALERT] = "ALERT",
[LOG_CRIT] = "CRIT",
[LOG_ERR] = "ERR",
[LOG_WARNING] = "WARN",
[LOG_NOTICE] = "NOTICE",
[LOG_INFO] = "INFO",
[LOG_DEBUG] = "DEBUG",
};
char const *const level_fmt_str[] = {
[LOG_FMT_FUNC_AND_LINE] = "FUNC_AND_LINE",
[LOG_FMT_TID] = "TID",
[LOG_FMT_LOG_TYPE] = "LOG_TYPE",
};
#define AR_SZ(a) (sizeof(a)/sizeof(a[0]))
#define BIT_SET(_v, _b) \
do { \
(_v) |= (1 << (_b));\
} while(0)
#define BIT_CLR(_v, _b) \
do { \
(_v) &= ~(1 << (_b));\
} while(0)
#define BIT_TOGGLE(_v, _b) \
do { \
(_v) ^= (1 << (_b)); \
} while(0)
int _log_fmt_is_set(enum log_fmt fmt)
{
if (_log_fmts & (1 << fmt)) {
return 1;
}
return 0;
}
void _log_fmt_set(enum log_fmt fmt)
{
BIT_SET(_log_fmts, fmt);
}
void _log_fmt_clr(enum log_fmt fmt)
{
BIT_CLR(_log_fmts, fmt);
}
void _log_fmt_toggle(enum log_fmt fmt)
{
BIT_TOGGLE(_log_fmts, fmt);
}
struct log_type_str_and_level {
char const *const name;
int level;
} log_type_str_and_level[] = {
/* TYPE有增減,請更新這個ARRAY */
[LOG_TYPE_AT] = { "AT", DEFAULT_LOG_LEVEL },
[LOG_TYPE_CORE] = { "CORE", DEFAULT_LOG_LEVEL },
[LOG_TYPE_DB] = { "DB", DEFAULT_LOG_LEVEL },
[LOG_TYPE_MAX] = { "MAX", DEFAULT_LOG_LEVEL },
};
char const *log_type_str(int type)
{
int i;
char buf[64], *p;
p = buf;
memset(buf, 0, sizeof(buf));
for (i = 0; i < AR_SZ(log_type_str_and_level); i++, type >>= 1) {
if (type & 1) {
p += snprintf(p, 64 - (p - buf), "%s/", log_type_str_and_level[i].name);
}
}
return buf;
}
int _log_type_level_is(enum log_type type, int *level)
{
if (type >= 0 && type < AR_SZ(log_type_str_and_level)) {
*level = log_type_str_and_level[type].level;
return 0;
}
return -1;
}
int _log_type_level_set(enum log_type type, int level)
{
if (type >= 0 && type < AR_SZ(log_type_str_and_level) && level >= 0 && level <= LOG_DEBUG) {
log_type_str_and_level[type].level = level;
return 0;
}
return -1;
}
int log_type_is_set(enum log_type type)
{
if (_log_types & (1 << type)) {
return 1;
}
return 0;
}
void _log_type_set(enum log_type type)
{
BIT_SET(_log_types, type);
}
void _log_type_clr(enum log_type type)
{
BIT_CLR(_log_types, type);
}
void _log_type_toggle(enum log_type type)
{
BIT_TOGGLE(_log_types, type);
}
void log_pr(int type, int level, char const *const fmt,...)
{
va_list ap;
int i;
if (_log_types & type) {
for (i = 0; i < AR_SZ(log_type_str_and_level); i++) {
if (log_type_str_and_level[i].level >= level) {
va_start(ap, fmt);
vsyslog(LOG_MAKEPRI(LOG_LOCAL0, level), fmt, ap);
va_end(ap);
return;
}
}
}
}
char *get_log_type_status_str(void)
{
int i = 0, re_sz;
static char buf[1024], *p;
p = buf;
re_sz = sizeof(buf);
p += snprintf(p, re_sz, "%2s %-16s %-10s %-12s\r\n", "id", "type", "status", "level");
for (i = 0; i < AR_SZ(log_type_str_and_level); i++) {
re_sz = sizeof(buf) - (p - buf);
if (re_sz < 1) {
break;
}
p += snprintf(p, re_sz, "%2d %-16s %-10s %-12s\r\n", i, log_type_str_and_level[i].name,
log_type_is_set((enum log_type)i) ? "enabled" : "disabled",
level_str[log_type_str_and_level[i].level]);
}
return buf;
}
char *get_log_fmt_status_str(void)
{
int i = 0, re_sz;
static char buf[256], *p;
p = buf;
re_sz = sizeof(buf);
p += snprintf(p, re_sz, "%2s %-16s %-12s\r\n", "id", "fmt", "status");
for (i = 0; i < AR_SZ(level_fmt_str); i++) {
re_sz = sizeof(buf) - (p - buf);
if (re_sz < 1) {
break;
}
p += snprintf(p, re_sz, "%2d %-16s %-12s\r\n", i, level_fmt_str[i],
_log_fmt_is_set((enum log_fmt)i) ? "enabled" : "disabled");
}
return buf;
}
void init_brook_log(void)
{
openlog(NULL, DEFAULT_LOG_OPTION, DEFAULT_LOG_FACILITY);
}
void exit_brook_log(void)
{
closelog();
}
void init_brook_log() __attribute__((constructor(101)));
void exit_brook_log() __attribute__((destructor(101)));
#include <stdio.h>
#include "brook-log.h"
int main(int argc, char *argv[])
{
pr_info(LOG_TYPE_BIT(AT) | LOG_TYPE_BIT(CORE), "AT=%d", 0);
log_type_clr(AT);
pr_info(LOG_TYPE_BIT(AT) | LOG_TYPE_BIT(CORE), "AT=%d", 1);
pr_info(LOG_TYPE_BIT(AT), "AT=%d", 11);
pr_info(LOG_TYPE_BIT(CORE), "AT=%d", 12);
log_type_set(AT);
pr_info(LOG_TYPE_BIT(AT) | LOG_TYPE_BIT(CORE), "AT=%d", 2);
log_fmt_toggle(FUNC_AND_LINE);
pr_info(LOG_TYPE_BIT(AT) | LOG_TYPE_BIT(CORE), "AT=%d", 3);
log_fmt_clr(TID);
pr_info(LOG_TYPE_BIT(AT) | LOG_TYPE_BIT(CORE), "AT=%d", 4);
log_type_level_set(AT, ERR);
pr_info(LOG_TYPE_BIT(AT) | LOG_TYPE_BIT(CORE), "AT=%d", 5);
return 0;
}
brook@vista:~/sample/syslog$ gcc main.c brook-log.c -o brook-log brook@vista:~/sample/syslog$ brook-log brook@vista:~/sample/syslog$ tail /var/log/local.log Nov 26 09:51:26 vista brook-log: main(#6), TID:21487, AT/CORE/, AT=0 Nov 26 09:51:26 vista brook-log: main(#9), TID:21487, AT/CORE/, AT=1 Nov 26 09:51:26 vista brook-log: main(#11), TID:21487, CORE/, AT=12 Nov 26 09:51:26 vista brook-log: main(#14), TID:21487, AT/CORE/, AT=2 Nov 26 09:51:26 vista brook-log: TID:21487, AT/CORE/, AT=3 Nov 26 09:51:26 vista brook-log: AT/CORE/, AT=4 Nov 26 09:51:26 vista brook-log: AT/CORE/, AT=5
如 if (length >= 10) 會比下面這行容易閱讀 if (10 <= length)
if (do_auth() != true) {
do_auth_failed();
return;
}
if (permission_check() != SUPER) {
do_permission_check_failed();
return;
}
do_something();
會比下面寫法容易閱讀
if (do_auth() == true) {
if (check_permission() == SUPER) {
do_something();
} else {
do_permission_check_failed();
{
} else {
do_auth_failed();
}