启动 skynet 使用的指令 ./skynet example/config 实际上就是调用 skynet-src/skynet_main.c main 函数
//skynet_main.c
int main(int argc, char *argv[]) {
//保存config文件地址的变量
const char * config_file = NULL ;
if (argc > 1) {
//读取配置文件config的地址,保存在config_file变量中
config_file = argv[1];
} else {
//不传入config文件地址会提示错误并结束程序
fprintf(stderr, "Need a config file. Please read skynet wiki : https://github.com/cloudwu/skynet/wiki/Config\n"
"usage: skynet configfilename\n");
return 1;
}
//初始化操作
luaS_initshr();
luaS_initshr()
初始化静态结构体SSM,SSM有个65536大小的数组结构体,对数组中的每个值调用rwlock_init赋值. rwlock.h中:
如果定义了USE_PTHREAD_LOCK: 则引用pthread.h,使用linux系统自带的线程库里的pthread_mutex_xxxx互斥API。
如果未定义USE_PTHREAD_LOCK:则利用原子操__sync_lock_test_and_set等来实现。
#define SHRSTR_SLOT 0x10000
#define HASH_NODE(h) ((h) % SHRSTR_SLOT)
#define getaddrstr(ts) (cast(char *, (ts)) + sizeof(UTString))
struct shrmap_slot {
struct rwlock lock;
TString *str;
};
struct shrmap {
struct shrmap_slot h[SHRSTR_SLOT];
int n;
};
static struct shrmap SSM;
LUA_API void
luaS_initshr() {
struct shrmap * s = &SSM;
int i;
for (i=0;i<SHRSTR_SLOT;i++) {
rwlock_init(&s->h[i].lock);
}
}
skynet_globalinit()
全局初始化,为线程特有数据使用pthread_key_create()函数创建一个key,然后使用pthread_setspecific()函数为这个key设置value值
void skynet_globalinit(void) {
G_NODE.total = 0;
G_NODE.monitor_exit = 0;
G_NODE.init = 1;
if (pthread_key_create(&G_NODE.handle_key, NULL)) {
fprintf(stderr, "pthread_key_create failed");
exit(1);
}
// set mainthread's key
skynet_initthread(THREAD_MAIN);
}
sigign() 设置信号处理函数,SIG_IGN表示忽略SIGPIPE那个注册的信号。
struct sigaction sa;
sa.sa_handler = SIG_IGN;
sigaction(SIGPIPE, &sa, 0);
return 0;
必要的数据被定义在一个 skynet-src/skynet_imp.h 中的 skynet_config 结构体内:
//skynet_imp.h
struct skynet_config {
int thread; //启动工作线程数量,不要配置超过实际拥有的CPU核心数
int harbor; //skynet网络节点的唯一编号,可以是 1-255 间的任意整数。一个 skynet 网络最多支持 255 个节点。每个节点有必须有一个唯一的编号。如果 harbor 为 0 ,skynet 工作在单节点模式下。此时 master 和 address 以及 standalone 都不必设置。
int profile; //是否开启统计功能,统计每个服务使用了多少cpu时间,默认开启
const char * daemon; //后台模式:daemon = "./skynet.pid"可以以后台模式启动skynet(注意,同时请配置logger 项输出log)
const char * module_path; //用 C 编写的服务模块的位置,通常指 cservice 下那些 .so 文件
const char * bootstrap; //skynet 启动的第一个服务以及其启动参数。默认配置为 snlua bootstrap ,即启动一个名为 bootstrap 的 lua 服务。通常指的是 service/bootstrap.lua 这段代码。
const char * logger; //它决定了 skynet 内建的 skynet_error 这个 C API 将信息输出到什么文件中。如果 logger 配置为 nil ,将输出到标准输出。你可以配置一个文件名来将信息记录在特定文件中。
const char * logservice; //默认为 "logger" ,你可以配置为你定制的 log 服务(比如加上时间戳等更多信息)。可以参考 service_logger.c 来实现它。注:如果你希望用 lua 来编写这个服务,可以在这里填写 snlua ,然后在 logger 配置具体的 lua 服务的名字。在 examples 目录下,有 config.userlog 这个范例可供参考。
};
完成环境设置 和 配置信息加载 之后调用skynet_start(&config)
参考资料