// mainloop thread static void forward_message(int type, bool padding, struct socket_message * result) { struct skynet_socket_message *sm; int sz = sizeof(*sm); if (padding) { if (result->data) { sz += strlen(result->data); } else { result->data = ""; } } sm = (struct skynet_socket_message *)skynet_malloc(sz); sm->type = type; sm->id = result->id; sm->ud = result->ud; if (padding) { sm->buffer = NULL; memcpy(sm+1, result->data, sz - sizeof(*sm)); } else { sm->buffer = result->data; } struct skynet_message message; message.source = 0; message.session = 0; message.data = sm; message.sz = sz | PTYPE_SOCKET << HANDLE_REMOTE_SHIFT; if (skynet_context_push((uint32_t)result->opaque, &message)) { // todo: report somewhere to close socket // don't call skynet_socket_close here (It will block mainloop) skynet_free(sm->buffer); skynet_free(sm); } }
void skynet_error(struct skynet_context * context, const char *msg, ...) { static uint32_t logger = 0; if (logger == 0) { logger = skynet_handle_findname("logger"); } if (logger == 0) { return; } char tmp[LOG_MESSAGE_SIZE]; char *data = NULL; va_list ap; va_start(ap, msg); int len = vsnprintf(tmp, LOG_MESSAGE_SIZE, msg, ap); va_end(ap); if (len < LOG_MESSAGE_SIZE) { data = skynet_strdup(tmp); } else { int max_size = LOG_MESSAGE_SIZE; for (;;) { max_size *= 2; data = skynet_malloc(max_size); va_start(ap, msg); len = vsnprintf(data, max_size, msg, ap); va_end(ap); if (len < max_size) { break; } skynet_free(data); } } struct skynet_message smsg; if (context == NULL) { smsg.source = 0; } else { smsg.source = skynet_context_handle(context); } smsg.session = 0; smsg.data = data; smsg.sz = len | (PTYPE_TEXT << HANDLE_REMOTE_SHIFT); skynet_context_push(logger, &smsg); }
static void timer_execute(struct timer *T) { while (__sync_lock_test_and_set(&T->lock,1)) {}; int idx=T->time & TIME_NEAR_MASK; struct timer_node *current; int mask,i,time; while (T->near[idx].head.next) { current=link_clear(&T->near[idx]); do { struct timer_event * event = (struct timer_event *)(current+1); struct skynet_message message; message.source = SKYNET_SYSTEM_TIMER; message.session = event->session; message.data = NULL; message.sz = 0; skynet_context_push(event->handle, &message); struct timer_node * temp = current; current=current->next; free(temp); } while (current); } ++T->time; mask = TIME_NEAR; time = T->time >> TIME_NEAR_SHIFT; i=0; while ((T->time & (mask-1))==0) { idx=time & TIME_LEVEL_MASK; if (idx!=0) { --idx; current=link_clear(&T->t[i][idx]); while (current) { struct timer_node *temp=current->next; add_node(T,current); current=temp; } break; } mask <<= TIME_LEVEL_SHIFT; time >>= TIME_LEVEL_SHIFT; ++i; } __sync_lock_release(&T->lock); }
/* 分发整个定时触发列表中的定时事件, 此函数要求列表中至少有一个定时事件节点. * 投递的消息类型为 PTYPE_RESPONSE, session 为注册定时器时传入的值, * 到 handle 也为注册定时器时传入的值为地址的服务中去. * 此函数同时负责将回收为 struct timer_node 结构分配的内存. */ static inline void dispatch_list(struct timer_node *current) { do { struct timer_event * event = (struct timer_event *)(current+1); struct skynet_message message; message.source = 0; message.session = event->session; message.data = NULL; message.sz = (size_t)PTYPE_RESPONSE << MESSAGE_TYPE_SHIFT; skynet_context_push(event->handle, &message); struct timer_node * temp = current; current=current->next; skynet_free(temp); } while (current); }
int skynet_timeout(uint32_t handle, int time, int session) { if (time == 0) { struct skynet_message message; message.source = SKYNET_SYSTEM_TIMER; message.session = session; message.data = NULL; message.sz = 0; if (skynet_context_push(handle, &message)) { return -1; } } else { struct timer_event event; event.handle = handle; event.session = session; timer_add(TI, &event, sizeof(event), time); } return session; }
/* 为一个服务的某次会话注册一个定时器事件. 如果传入的时间小于等于 0 将会立即发送 * 类型为 PTYPE_RESPONSE 的消息给该服务会话, 否则将以线程安全的方式添加到触发列表集中. * 参数 handle 是服务地址, time 是距离现在的触发时间单位是厘秒, session 是服务中的会话. * 此函数是线程安全的. */ int skynet_timeout(uint32_t handle, int time, int session) { if (time <= 0) { struct skynet_message message; message.source = 0; message.session = session; message.data = NULL; message.sz = (size_t)PTYPE_RESPONSE << MESSAGE_TYPE_SHIFT; if (skynet_context_push(handle, &message)) { return -1; } } else { struct timer_event event; event.handle = handle; event.session = session; timer_add(TI, &event, sizeof(event), time); } return session; }
static inline void timer_execute(struct timer *T) { int idx = T->time & TIME_NEAR_MASK; while (T->near[idx].head.next) { struct timer_node *current = link_clear(&T->near[idx]); do { struct timer_event * event = (struct timer_event *)(current+1); struct skynet_message message; message.source = 0; message.session = event->session; message.data = NULL; message.sz = PTYPE_RESPONSE << HANDLE_REMOTE_SHIFT; skynet_context_push(event->handle, &message); struct timer_node * temp = current; current=current->next; skynet_free(temp); } while (current); } }