123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293 |
- #include "skynet.h"
- #include "skynet_timer.h"
- #include "skynet_mq.h"
- #include "skynet_server.h"
- #include "skynet_handle.h"
- #include "spinlock.h"
- #include <time.h>
- #include <assert.h>
- #include <string.h>
- #include <stdlib.h>
- #include <stdint.h>
- typedef void (*timer_execute_func)(void *ud,void *arg);
- #define TIME_NEAR_SHIFT 8
- #define TIME_NEAR (1 << TIME_NEAR_SHIFT)
- #define TIME_LEVEL_SHIFT 6
- #define TIME_LEVEL (1 << TIME_LEVEL_SHIFT)
- #define TIME_NEAR_MASK (TIME_NEAR-1)
- #define TIME_LEVEL_MASK (TIME_LEVEL-1)
- struct timer_event {
- uint32_t handle;
- int session;
- };
- struct timer_node {
- struct timer_node *next;
- uint32_t expire;
- };
- struct link_list {
- struct timer_node head;
- struct timer_node *tail;
- };
- struct timer {
- struct link_list near[TIME_NEAR];
- struct link_list t[4][TIME_LEVEL];
- struct spinlock lock;
- uint32_t time;
- uint32_t starttime;
- uint64_t current;
- uint64_t current_point;
- };
- static struct timer * TI = NULL;
- static inline struct timer_node *
- link_clear(struct link_list *list) {
- struct timer_node * ret = list->head.next;
- list->head.next = 0;
- list->tail = &(list->head);
- return ret;
- }
- static inline void
- link(struct link_list *list,struct timer_node *node) {
- list->tail->next = node;
- list->tail = node;
- node->next=0;
- }
- static void
- add_node(struct timer *T,struct timer_node *node) {
- uint32_t time=node->expire;
- uint32_t current_time=T->time;
-
- if ((time|TIME_NEAR_MASK)==(current_time|TIME_NEAR_MASK)) {
- link(&T->near[time&TIME_NEAR_MASK],node);
- } else {
- int i;
- uint32_t mask=TIME_NEAR << TIME_LEVEL_SHIFT;
- for (i=0;i<3;i++) {
- if ((time|(mask-1))==(current_time|(mask-1))) {
- break;
- }
- mask <<= TIME_LEVEL_SHIFT;
- }
- link(&T->t[i][((time>>(TIME_NEAR_SHIFT + i*TIME_LEVEL_SHIFT)) & TIME_LEVEL_MASK)],node);
- }
- }
- static void
- timer_add(struct timer *T,void *arg,size_t sz,int time) {
- struct timer_node *node = (struct timer_node *)skynet_malloc(sizeof(*node)+sz);
- memcpy(node+1,arg,sz);
- SPIN_LOCK(T);
- node->expire=time+T->time;
- add_node(T,node);
- SPIN_UNLOCK(T);
- }
- static void
- move_list(struct timer *T, int level, int idx) {
- struct timer_node *current = link_clear(&T->t[level][idx]);
- while (current) {
- struct timer_node *temp=current->next;
- add_node(T,current);
- current=temp;
- }
- }
- static void
- timer_shift(struct timer *T) {
- int mask = TIME_NEAR;
- uint32_t ct = ++T->time;
- if (ct == 0) {
- move_list(T, 3, 0);
- } else {
- uint32_t time = ct >> TIME_NEAR_SHIFT;
- int i=0;
- while ((ct & (mask-1))==0) {
- int idx=time & TIME_LEVEL_MASK;
- if (idx!=0) {
- move_list(T, i, idx);
- break;
- }
- mask <<= TIME_LEVEL_SHIFT;
- time >>= TIME_LEVEL_SHIFT;
- ++i;
- }
- }
- }
- 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);
- }
- 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]);
- SPIN_UNLOCK(T);
- // dispatch_list don't need lock T
- dispatch_list(current);
- SPIN_LOCK(T);
- }
- }
- static void
- timer_update(struct timer *T) {
- SPIN_LOCK(T);
- // try to dispatch timeout 0 (rare condition)
- timer_execute(T);
- // shift time first, and then dispatch timer message
- timer_shift(T);
- timer_execute(T);
- SPIN_UNLOCK(T);
- }
- static struct timer *
- timer_create_timer() {
- struct timer *r=(struct timer *)skynet_malloc(sizeof(struct timer));
- memset(r,0,sizeof(*r));
- int i,j;
- for (i=0;i<TIME_NEAR;i++) {
- link_clear(&r->near[i]);
- }
- for (i=0;i<4;i++) {
- for (j=0;j<TIME_LEVEL;j++) {
- link_clear(&r->t[i][j]);
- }
- }
- SPIN_INIT(r)
- r->current = 0;
- return r;
- }
- 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;
- }
- // centisecond: 1/100 second
- static void
- systime(uint32_t *sec, uint32_t *cs) {
- struct timespec ti;
- clock_gettime(CLOCK_REALTIME, &ti);
- *sec = (uint32_t)ti.tv_sec;
- *cs = (uint32_t)(ti.tv_nsec / 10000000);
- }
- static uint64_t
- gettime() {
- uint64_t t;
- struct timespec ti;
- clock_gettime(CLOCK_MONOTONIC, &ti);
- t = (uint64_t)ti.tv_sec * 100;
- t += ti.tv_nsec / 10000000;
- return t;
- }
- void
- skynet_updatetime(void) {
- uint64_t cp = gettime();
- if(cp < TI->current_point) {
- skynet_error(NULL, "time diff error: change from %lld to %lld", cp, TI->current_point);
- TI->current_point = cp;
- } else if (cp != TI->current_point) {
- uint32_t diff = (uint32_t)(cp - TI->current_point);
- TI->current_point = cp;
- TI->current += diff;
- int i;
- for (i=0;i<diff;i++) {
- timer_update(TI);
- }
- }
- }
- uint32_t
- skynet_starttime(void) {
- return TI->starttime;
- }
- uint64_t
- skynet_now(void) {
- return TI->current;
- }
- void
- skynet_timer_init(void) {
- TI = timer_create_timer();
- uint32_t current = 0;
- systime(&TI->starttime, ¤t);
- TI->current = current;
- TI->current_point = gettime();
- }
- // for profile
- #define NANOSEC 1000000000
- #define MICROSEC 1000000
- uint64_t
- skynet_thread_time(void) {
- struct timespec ti;
- clock_gettime(CLOCK_THREAD_CPUTIME_ID, &ti);
- return (uint64_t)ti.tv_sec * MICROSEC + (uint64_t)ti.tv_nsec / (NANOSEC / MICROSEC);
- }
|