hustxiaoc/node.js

Node.js timer

hustxiaoc opened this issue · 1 comments

a simple timer based on kqueue and min binary heap

#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/event.h>
#include <sys/time.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <errno.h>

//https://github.com/joyent/libuv/blob/master/src/heap-inl.h
#include "heap-inl.h"

#define container_of(ptr, type, member) \
  ((type *) ((char *) (ptr) - offsetof(type, member)))

const int MAX_EVENT_COUNT = 5000;

typedef struct {
    struct heap_node* heap_node[3];
    int value;
}node_t;

static int less_than(const struct heap_node* ha, const struct heap_node* hb) {
    const node_t* a;
      const node_t* b;

    a = container_of(ha, const node_t, heap_node);
    b = container_of(hb, const node_t, heap_node);

    if (a->value < b->value)
      return 1;
    return 0;
}


int main() {

  struct heap *heap_p = malloc(sizeof(node_t));
  heap_init(heap_p);

  int a[] = {10,9,8,6,7,3,5,4,2};

  int len = sizeof(a)/sizeof(int);
  for(int i=0;i<len;i++){
    node_t *node_p = malloc(sizeof(node_t));
    node_p->value = a[i]*1000;
    heap_insert(heap_p, (struct heap_node*)node_p->heap_node, less_than);
  }


  int fd = socket(PF_INET, SOCK_STREAM,0);
  int kq = kqueue();

  struct kevent changes[1];
  EV_SET(&changes[0], fd, EVFILT_READ, EV_ADD, 0, 0, NULL);

  struct kevent events[MAX_EVENT_COUNT];
  time_t last_time = time(NULL);
  while(heap_p->nelts) {
      node_t *node_p = container_of(heap_p->min, node_t, heap_node);
      struct timespec spec;
      spec.tv_sec = node_p->value / 1000;
      spec.tv_nsec = (node_p->value % 1000) * 1000000;
      kevent(kq, NULL, 0, events, MAX_EVENT_COUNT, &spec);
      heap_dequeue(heap_p, less_than);
      printf("timeout = %d, run time is %ld\n", node_p->value, time(NULL)-last_time);
      last_time = time(NULL);
  }

  printf("timer is over!\n");

  return 0;
}

run the code ,you'll get

timeout = 2000, run time is 2
timeout = 3000, run time is 3
timeout = 4000, run time is 4
timeout = 5000, run time is 5
timeout = 6000, run time is 6
timeout = 7000, run time is 7
timeout = 8000, run time is 8
timeout = 9000, run time is 9
timeout = 10000, run time is 10
timer is over!

exactly as we expected!

/*
Swap parent with child. Child moves closer to the root, parent moves away.
the official heap_node_swap actually just moves the pointer but it indeed does not have a data pointer. and heap_node_swap below moves both, the pointer self and it's data pointer
*/

static void heap_node_swap(struct heap* heap,
                           struct heap_node* parent,
                           struct heap_node* child) {
  int left;
  struct heap_node* sibling;

  child->parent = parent->parent;
  parent->parent = child;

  if(child->parent != NULL) {
    if(child->parent->left == parent) {
        child->parent->left = child;
    }else{
        child->parent->right = child;
    }
  }else {
    heap->min = child;
  }

  left = (parent->left == child)? 1:0;

  sibling = left ? parent->right: parent->left;

  parent->left = child->left;
  parent->right = child->right;
  if(child->left != NULL) {
     parent->left->parent = parent;
  }
   if(child->right != NULL) {
    parent->right->parent = parent;
  }

  if(left) {
      child->left = parent;
      child->right = sibling;
  }else{
      child->right = parent;
      child->left = sibling;
  }

  if(sibling != NULL) {
      sibling->parent = child;
  }
}