mirror of
https://github.com/cloudwu/skynet.git
synced 2026-07-24 20:23:06 +00:00
change source dir
This commit is contained in:
48
skynet-src/rwlock.h
Normal file
48
skynet-src/rwlock.h
Normal file
@@ -0,0 +1,48 @@
|
||||
#ifndef _RWLOCK_H_
|
||||
#define _RWLOCK_H_
|
||||
|
||||
struct rwlock {
|
||||
int write;
|
||||
int read;
|
||||
};
|
||||
|
||||
static inline void
|
||||
rwlock_init(struct rwlock *lock) {
|
||||
lock->write = 0;
|
||||
lock->read = 0;
|
||||
}
|
||||
|
||||
static inline void
|
||||
rwlock_rlock(struct rwlock *lock) {
|
||||
for (;;) {
|
||||
while(lock->write) {
|
||||
__sync_synchronize();
|
||||
}
|
||||
__sync_add_and_fetch(&lock->read,1);
|
||||
if (lock->write) {
|
||||
__sync_sub_and_fetch(&lock->read,1);
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
rwlock_wlock(struct rwlock *lock) {
|
||||
__sync_lock_test_and_set(&lock->write,1);
|
||||
while(lock->read) {
|
||||
__sync_synchronize();
|
||||
}
|
||||
}
|
||||
|
||||
static inline void
|
||||
rwlock_wunlock(struct rwlock *lock) {
|
||||
__sync_lock_release(&lock->write);
|
||||
}
|
||||
|
||||
static inline void
|
||||
rwlock_runlock(struct rwlock *lock) {
|
||||
__sync_sub_and_fetch(&lock->read,1);
|
||||
}
|
||||
|
||||
#endif
|
||||
19
skynet-src/skynet.h
Normal file
19
skynet-src/skynet.h
Normal file
@@ -0,0 +1,19 @@
|
||||
#ifndef SKYNET_H
|
||||
#define SKYNET_H
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
#define DONTCOPY 1
|
||||
|
||||
struct skynet_context;
|
||||
|
||||
void skynet_error(struct skynet_context * context, const char *msg, ...);
|
||||
const char * skynet_command(struct skynet_context * context, const char * cmd , const char * parm);
|
||||
int skynet_send(struct skynet_context * context, const char * addr , int session, void * msg, size_t sz, int flags);
|
||||
|
||||
void skynet_forward(struct skynet_context *, const char * addr);
|
||||
typedef void (*skynet_cb)(struct skynet_context * context, void *ud, int session, const char * addr , const void * msg, size_t sz);
|
||||
void skynet_callback(struct skynet_context * context, void *ud, skynet_cb cb);
|
||||
|
||||
#endif
|
||||
53
skynet-src/skynet_env.c
Normal file
53
skynet-src/skynet_env.c
Normal file
@@ -0,0 +1,53 @@
|
||||
#include "skynet_env.h"
|
||||
|
||||
#include <lua.h>
|
||||
#include <lauxlib.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
|
||||
struct skynet_env {
|
||||
int lock;
|
||||
lua_State *L;
|
||||
};
|
||||
|
||||
static struct skynet_env *E = NULL;
|
||||
|
||||
#define LOCK(q) while (__sync_lock_test_and_set(&(q)->lock,1)) {}
|
||||
#define UNLOCK(q) __sync_lock_release(&(q)->lock);
|
||||
|
||||
const char *
|
||||
skynet_getenv(const char *key) {
|
||||
LOCK(E)
|
||||
|
||||
lua_State *L = E->L;
|
||||
|
||||
lua_getglobal(L, key);
|
||||
const char * result = lua_tostring(L, -1);
|
||||
lua_pop(L, 1);
|
||||
|
||||
UNLOCK(E)
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
skynet_setenv(const char *key, const char *value) {
|
||||
LOCK(E)
|
||||
|
||||
lua_State *L = E->L;
|
||||
lua_getglobal(L, key);
|
||||
assert(lua_isnil(L, -1));
|
||||
lua_pop(L,1);
|
||||
lua_pushstring(L,value);
|
||||
lua_setglobal(L,key);
|
||||
|
||||
UNLOCK(E)
|
||||
}
|
||||
|
||||
void
|
||||
skynet_env_init() {
|
||||
E = malloc(sizeof(*E));
|
||||
E->lock = 0;
|
||||
E->L = luaL_newstate();
|
||||
}
|
||||
9
skynet-src/skynet_env.h
Normal file
9
skynet-src/skynet_env.h
Normal file
@@ -0,0 +1,9 @@
|
||||
#ifndef SKYNET_ENV_H
|
||||
#define SKYNET_ENV_H
|
||||
|
||||
const char * skynet_getenv(const char *key);
|
||||
void skynet_setenv(const char *key, const char *value);
|
||||
|
||||
void skynet_env_init();
|
||||
|
||||
#endif
|
||||
46
skynet-src/skynet_error.c
Normal file
46
skynet-src/skynet_error.c
Normal file
@@ -0,0 +1,46 @@
|
||||
#include "skynet.h"
|
||||
#include "skynet_handle.h"
|
||||
#include "skynet_mq.h"
|
||||
#include "skynet_server.h"
|
||||
#include "skynet_system.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#define LOG_MESSAGE_SIZE 1024
|
||||
|
||||
void
|
||||
skynet_error(struct skynet_context * context, const char *msg, ...) {
|
||||
static int logger = -1;
|
||||
if (logger < 0) {
|
||||
logger = skynet_handle_findname("logger");
|
||||
}
|
||||
if (logger < 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
char tmp[LOG_MESSAGE_SIZE];
|
||||
|
||||
va_list ap;
|
||||
va_start(ap,msg);
|
||||
int len = vsnprintf(tmp, LOG_MESSAGE_SIZE, msg, ap);
|
||||
va_end(ap);
|
||||
|
||||
if (len >= LOG_MESSAGE_SIZE) {
|
||||
len = LOG_MESSAGE_SIZE - 1;
|
||||
tmp[len] = '\0';
|
||||
}
|
||||
|
||||
struct skynet_message smsg;
|
||||
if (context == NULL) {
|
||||
smsg.source = SKYNET_SYSTEM_LOGGER;
|
||||
} else {
|
||||
smsg.source = skynet_context_handle(context);
|
||||
}
|
||||
smsg.session = 0;
|
||||
smsg.data = strdup(tmp);
|
||||
smsg.sz = len;
|
||||
skynet_context_push(logger, &smsg);
|
||||
}
|
||||
|
||||
225
skynet-src/skynet_handle.c
Normal file
225
skynet-src/skynet_handle.c
Normal file
@@ -0,0 +1,225 @@
|
||||
#include "skynet_handle.h"
|
||||
#include "skynet_server.h"
|
||||
#include "rwlock.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
|
||||
#define DEFAULT_SLOT_SIZE 4
|
||||
|
||||
struct handle_name {
|
||||
char * name;
|
||||
uint32_t handle;
|
||||
};
|
||||
|
||||
struct handle_storage {
|
||||
struct rwlock lock;
|
||||
|
||||
uint32_t harbor;
|
||||
uint32_t handle_index;
|
||||
int slot_size;
|
||||
struct skynet_context ** slot;
|
||||
|
||||
int name_cap;
|
||||
int name_count;
|
||||
struct handle_name *name;
|
||||
};
|
||||
|
||||
static struct handle_storage *H = NULL;
|
||||
|
||||
uint32_t
|
||||
skynet_handle_register(struct skynet_context *ctx) {
|
||||
struct handle_storage *s = H;
|
||||
|
||||
rwlock_wlock(&s->lock);
|
||||
|
||||
for (;;) {
|
||||
int i;
|
||||
for (i=0;i<s->slot_size;i++) {
|
||||
uint32_t handle = (i+s->handle_index) & HANDLE_MASK;
|
||||
int hash = handle & (s->slot_size-1);
|
||||
if (s->slot[hash] == NULL) {
|
||||
s->slot[hash] = ctx;
|
||||
s->handle_index = handle + 1;
|
||||
|
||||
rwlock_wunlock(&s->lock);
|
||||
|
||||
handle |= s->harbor;
|
||||
skynet_context_init(ctx, handle);
|
||||
return handle;
|
||||
}
|
||||
}
|
||||
assert((s->slot_size*2 - 1) <= HANDLE_MASK);
|
||||
struct skynet_context ** new_slot = malloc(s->slot_size * 2 * sizeof(struct skynet_context *));
|
||||
memset(new_slot, 0, s->slot_size * 2 * sizeof(struct skynet_context *));
|
||||
for (i=0;i<s->slot_size;i++) {
|
||||
int hash = skynet_context_handle(s->slot[i]) & (s->slot_size * 2 - 1);
|
||||
assert(new_slot[hash] == NULL);
|
||||
new_slot[hash] = s->slot[i];
|
||||
}
|
||||
free(s->slot);
|
||||
s->slot = new_slot;
|
||||
s->slot_size *= 2;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
skynet_handle_retire(uint32_t handle) {
|
||||
struct handle_storage *s = H;
|
||||
|
||||
rwlock_wlock(&s->lock);
|
||||
|
||||
uint32_t hash = handle & (s->slot_size-1);
|
||||
struct skynet_context * ctx = s->slot[hash];
|
||||
if (skynet_context_handle(ctx) == handle) {
|
||||
skynet_context_release(ctx);
|
||||
s->slot[hash] = NULL;
|
||||
|
||||
int i;
|
||||
int j=0, n=s->name_count;
|
||||
for (i=0; i<n; ++i) {
|
||||
if (s->name[i].handle == handle) {
|
||||
free(s->name[i].name);
|
||||
continue;
|
||||
} else if (i!=j) {
|
||||
s->name[j] = s->name[i];
|
||||
}
|
||||
++j;
|
||||
}
|
||||
s->name_count = j;
|
||||
}
|
||||
|
||||
rwlock_wunlock(&s->lock);
|
||||
}
|
||||
|
||||
struct skynet_context *
|
||||
skynet_handle_grab(uint32_t handle) {
|
||||
struct handle_storage *s = H;
|
||||
struct skynet_context * result = NULL;
|
||||
|
||||
rwlock_rlock(&s->lock);
|
||||
|
||||
uint32_t hash = handle & (s->slot_size-1);
|
||||
struct skynet_context * ctx = s->slot[hash];
|
||||
if (ctx && skynet_context_handle(ctx) == handle) {
|
||||
result = ctx;
|
||||
skynet_context_grab(result);
|
||||
}
|
||||
|
||||
rwlock_runlock(&s->lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
skynet_handle_findname(const char * name) {
|
||||
struct handle_storage *s = H;
|
||||
|
||||
rwlock_rlock(&s->lock);
|
||||
|
||||
uint32_t handle = 0;
|
||||
|
||||
int begin = 0;
|
||||
int end = s->name_count - 1;
|
||||
while (begin<=end) {
|
||||
int mid = (begin+end)/2;
|
||||
struct handle_name *n = &s->name[mid];
|
||||
int c = strcmp(n->name, name);
|
||||
if (c==0) {
|
||||
handle = n->handle;
|
||||
break;
|
||||
}
|
||||
if (c<0) {
|
||||
begin = mid + 1;
|
||||
} else {
|
||||
end = mid - 1;
|
||||
}
|
||||
}
|
||||
|
||||
rwlock_runlock(&s->lock);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
static void
|
||||
_insert_name_before(struct handle_storage *s, char *name, uint32_t handle, int before) {
|
||||
if (s->name_count >= s->name_cap) {
|
||||
s->name_cap *= 2;
|
||||
struct handle_name * n = malloc(s->name_cap * sizeof(struct handle_name));
|
||||
int i;
|
||||
for (i=0;i<before;i++) {
|
||||
n[i] = s->name[i];
|
||||
}
|
||||
for (i=before;i<s->name_count;i++) {
|
||||
n[i+1] = s->name[i];
|
||||
}
|
||||
free(s->name);
|
||||
s->name = n;
|
||||
} else {
|
||||
int i;
|
||||
for (i=s->name_count;i>=before;i--) {
|
||||
s->name[i] = s->name[i-1];
|
||||
}
|
||||
}
|
||||
s->name[before].name = name;
|
||||
s->name[before].handle = handle;
|
||||
s->name_count ++;
|
||||
}
|
||||
|
||||
static const char *
|
||||
_insert_name(struct handle_storage *s, const char * name, uint32_t handle) {
|
||||
int begin = 0;
|
||||
int end = s->name_count - 1;
|
||||
while (begin<=end) {
|
||||
int mid = (begin+end)/2;
|
||||
struct handle_name *n = &s->name[mid];
|
||||
int c = strcmp(n->name, name);
|
||||
if (c==0) {
|
||||
return NULL;
|
||||
}
|
||||
if (c<0) {
|
||||
begin = mid + 1;
|
||||
} else {
|
||||
end = mid - 1;
|
||||
}
|
||||
}
|
||||
char * result = strdup(name);
|
||||
|
||||
_insert_name_before(s, result, handle, begin);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
const char *
|
||||
skynet_handle_namehandle(uint32_t handle, const char *name) {
|
||||
rwlock_wlock(&H->lock);
|
||||
|
||||
const char * ret = _insert_name(H, name, handle);
|
||||
|
||||
rwlock_wunlock(&H->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
skynet_handle_init(int harbor) {
|
||||
assert(H==NULL);
|
||||
struct handle_storage * s = malloc(sizeof(*H));
|
||||
s->slot_size = DEFAULT_SLOT_SIZE;
|
||||
s->slot = malloc(s->slot_size * sizeof(struct skynet_context *));
|
||||
memset(s->slot, 0, s->slot_size * sizeof(struct handle_slot *));
|
||||
|
||||
rwlock_init(&s->lock);
|
||||
// reserve 0 for system
|
||||
s->harbor = (uint32_t) (harbor & 0xff) << HANDLE_REMOTE_SHIFT;
|
||||
s->handle_index = 1;
|
||||
s->name_cap = 2;
|
||||
s->name_count = 0;
|
||||
s->name = malloc(s->name_cap * sizeof(struct handle_name));
|
||||
|
||||
H = s;
|
||||
|
||||
// Don't need to free H
|
||||
}
|
||||
|
||||
22
skynet-src/skynet_handle.h
Normal file
22
skynet-src/skynet_handle.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#ifndef SKYNET_CONTEXT_HANDLE_H
|
||||
#define SKYNET_CONTEXT_HANDLE_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
// reserve high 8 bits for remote id
|
||||
// see skynet_harbor.c REMOTE_MAX
|
||||
#define HANDLE_MASK 0xffffff
|
||||
#define HANDLE_REMOTE_SHIFT 24
|
||||
|
||||
struct skynet_context;
|
||||
|
||||
uint32_t skynet_handle_register(struct skynet_context *);
|
||||
void skynet_handle_retire(uint32_t handle);
|
||||
struct skynet_context * skynet_handle_grab(uint32_t handle);
|
||||
|
||||
uint32_t skynet_handle_findname(const char * name);
|
||||
const char * skynet_handle_namehandle(uint32_t handle, const char *name);
|
||||
|
||||
void skynet_handle_init(int harbor);
|
||||
|
||||
#endif
|
||||
670
skynet-src/skynet_harbor.c
Normal file
670
skynet-src/skynet_harbor.c
Normal file
@@ -0,0 +1,670 @@
|
||||
#include "skynet_harbor.h"
|
||||
#include "skynet_mq.h"
|
||||
#include "skynet_handle.h"
|
||||
#include "skynet_system.h"
|
||||
#include "skynet_server.h"
|
||||
#include "skynet.h"
|
||||
|
||||
#include <zmq.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdio.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define HASH_SIZE 4096
|
||||
#define DEFAULT_QUEUE_SIZE 1024
|
||||
|
||||
// see skynet_handle.h for HANDLE_REMOTE_SHIFT
|
||||
#define REMOTE_MAX 255
|
||||
|
||||
struct keyvalue {
|
||||
struct keyvalue * next;
|
||||
uint32_t hash;
|
||||
char * key;
|
||||
uint32_t value;
|
||||
struct message_queue * queue;
|
||||
};
|
||||
|
||||
struct hashmap {
|
||||
struct keyvalue *node[HASH_SIZE];
|
||||
};
|
||||
|
||||
struct remote_header {
|
||||
uint32_t source;
|
||||
uint32_t destination;
|
||||
uint32_t session;
|
||||
};
|
||||
|
||||
struct remote {
|
||||
void *socket;
|
||||
struct message_remote_queue *queue;
|
||||
};
|
||||
|
||||
struct harbor {
|
||||
void * zmq_context;
|
||||
void * zmq_master_request;
|
||||
void * zmq_local;
|
||||
void * zmq_queue_notice;
|
||||
int notice_event;
|
||||
struct hashmap *map;
|
||||
struct remote remote[REMOTE_MAX];
|
||||
struct message_remote_queue *queue;
|
||||
int harbor;
|
||||
|
||||
int lock;
|
||||
};
|
||||
|
||||
static struct harbor *Z = NULL;
|
||||
|
||||
// todo: optimize for little endian system
|
||||
|
||||
static inline void
|
||||
buffer_to_remote_header(uint8_t *buffer, struct remote_header *header) {
|
||||
header->source = buffer[0] | buffer[1] << 8 | buffer[2] << 16 | buffer[3] << 24;
|
||||
header->destination = buffer[4] | buffer[5] << 8 | buffer[6] << 16 | buffer[7] << 24;
|
||||
header->session = buffer[8] | buffer[9] << 8 | buffer[10] << 16 | buffer[11] << 24;
|
||||
}
|
||||
|
||||
static inline void
|
||||
remote_header_to_buffer(struct remote_header *header, uint8_t *buffer) {
|
||||
buffer[0] = header->source & 0xff;
|
||||
buffer[1] = (header->source >> 8) & 0xff;
|
||||
buffer[2] = (header->source >>16) & 0xff;
|
||||
buffer[3] = (header->source >>24)& 0xff;
|
||||
buffer[4] = (header->destination) & 0xff;
|
||||
buffer[5] = (header->destination >>8) & 0xff;
|
||||
buffer[6] = (header->destination >>16) & 0xff;
|
||||
buffer[7] = (header->destination >>24) & 0xff;
|
||||
buffer[8] = (header->session) & 0xff;
|
||||
buffer[9] = (header->session >>8) & 0xff;
|
||||
buffer[10] = (header->session >>16) & 0xff;
|
||||
buffer[11] = (header->session >>24) & 0xff;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
calc_hash(const char *name) {
|
||||
int i;
|
||||
uint32_t h = 0;
|
||||
for (i=0;name[i];i++) {
|
||||
h = h ^ ((h<<5)+(h>>2)+(uint8_t)name[i]);
|
||||
}
|
||||
h ^= i;
|
||||
return h;
|
||||
}
|
||||
|
||||
static inline void
|
||||
_lock() {
|
||||
while (__sync_lock_test_and_set(&Z->lock,1)) {}
|
||||
}
|
||||
|
||||
static inline void
|
||||
_unlock() {
|
||||
__sync_lock_release(&Z->lock);
|
||||
}
|
||||
|
||||
static struct hashmap *
|
||||
_hash_new(void) {
|
||||
struct hashmap * hash = malloc(sizeof(*hash));
|
||||
memset(hash, 0, sizeof(*hash));
|
||||
return hash;
|
||||
}
|
||||
|
||||
static struct keyvalue *
|
||||
_hash_search(struct hashmap * hash, const char * key) {
|
||||
uint32_t h = calc_hash(key);
|
||||
struct keyvalue * n = hash->node[h & (HASH_SIZE-1)];
|
||||
while (n) {
|
||||
if (n->hash == h && strcmp(n->key, key) == 0) {
|
||||
return n;
|
||||
}
|
||||
n = n->next;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
_hash_insert(struct hashmap * hash, const char * key, uint32_t handle, struct message_queue *queue) {
|
||||
uint32_t h = calc_hash(key);
|
||||
struct keyvalue * node = malloc(sizeof(*node));
|
||||
node->next = hash->node[h & (HASH_SIZE-1)];
|
||||
node->hash = h;
|
||||
node->key = strdup(key);
|
||||
node->value = handle;
|
||||
node->queue = queue;
|
||||
|
||||
hash->node[h & (HASH_SIZE-1)] = node;
|
||||
}
|
||||
|
||||
// thread safe function
|
||||
static void
|
||||
send_notice() {
|
||||
if (__sync_lock_test_and_set(&Z->notice_event,1)) {
|
||||
// already send notice
|
||||
return;
|
||||
}
|
||||
static __thread void * queue_notice = NULL;
|
||||
if (queue_notice == NULL) {
|
||||
void * pub = zmq_socket(Z->zmq_context, ZMQ_PUSH);
|
||||
int r = zmq_connect(pub , "inproc://notice");
|
||||
assert(r==0);
|
||||
queue_notice = pub;
|
||||
}
|
||||
zmq_msg_t dummy;
|
||||
zmq_msg_init(&dummy);
|
||||
zmq_send(queue_notice,&dummy,0);
|
||||
zmq_msg_close(&dummy);
|
||||
}
|
||||
|
||||
// thread safe function
|
||||
void
|
||||
skynet_harbor_send(const char *name, uint32_t destination, struct skynet_message * msg) {
|
||||
if (name == NULL) {
|
||||
assert(destination!=0);
|
||||
int remote_id = destination >> HANDLE_REMOTE_SHIFT;
|
||||
assert(remote_id > 0 && remote_id <= REMOTE_MAX);
|
||||
struct skynet_remote_message message;
|
||||
message.destination = destination;
|
||||
message.message = *msg;
|
||||
skynet_remotemq_push(Z->queue, &message);
|
||||
send_notice();
|
||||
} else {
|
||||
_lock();
|
||||
struct keyvalue * node = _hash_search(Z->map, name);
|
||||
if (node) {
|
||||
uint32_t dest = node->value;
|
||||
_unlock();
|
||||
if (dest == 0) {
|
||||
// push message to unknown name service queue
|
||||
skynet_mq_push(node->queue, msg);
|
||||
} else {
|
||||
if (!skynet_harbor_message_isremote(dest)) {
|
||||
// local message
|
||||
if (skynet_context_push(dest, msg)) {
|
||||
skynet_error(NULL, "Drop local message from %u to %s",msg->source, name);
|
||||
}
|
||||
return;
|
||||
}
|
||||
struct skynet_remote_message message;
|
||||
message.destination = dest;
|
||||
message.message = *msg;
|
||||
skynet_remotemq_push(Z->queue,&message);
|
||||
send_notice();
|
||||
}
|
||||
} else {
|
||||
// never seen name before
|
||||
struct message_queue * queue = skynet_mq_create(0);
|
||||
skynet_mq_push(queue, msg);
|
||||
_hash_insert(Z->map, name, 0, queue);
|
||||
_unlock();
|
||||
// 0 for query
|
||||
skynet_harbor_register(name,0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// thread safe function
|
||||
//queue a register message (destination = 0)
|
||||
void
|
||||
skynet_harbor_register(const char *name, uint32_t handle) {
|
||||
struct skynet_remote_message msg;
|
||||
msg.destination = SKYNET_SYSTEM_NAME;
|
||||
msg.message.source = handle;
|
||||
msg.message.data = strdup(name);
|
||||
|
||||
msg.message.sz = 0;
|
||||
skynet_remotemq_push(Z->queue,&msg);
|
||||
send_notice();
|
||||
}
|
||||
|
||||
// Always in main harbor thread
|
||||
static void
|
||||
_register_name(const char *name, uint32_t addr) {
|
||||
_lock();
|
||||
struct keyvalue * node = _hash_search(Z->map, name);
|
||||
if (node) {
|
||||
if (node->value) {
|
||||
node->value = addr;
|
||||
assert(node->queue == NULL);
|
||||
} else {
|
||||
node->value = addr;
|
||||
}
|
||||
} else {
|
||||
_hash_insert(Z->map, name, addr, NULL);
|
||||
}
|
||||
|
||||
if (addr == 0) {
|
||||
_unlock();
|
||||
return;
|
||||
}
|
||||
|
||||
struct skynet_message msg;
|
||||
struct message_queue * queue = node ? node->queue : NULL;
|
||||
|
||||
if (queue) {
|
||||
if (skynet_harbor_message_isremote(addr)) {
|
||||
while (!skynet_mq_pop(queue, &msg)) {
|
||||
struct skynet_remote_message message;
|
||||
message.destination = addr;
|
||||
message.message = msg;
|
||||
skynet_remotemq_push(Z->queue, &message);
|
||||
send_notice();
|
||||
}
|
||||
} else {
|
||||
while (!skynet_mq_pop(queue, &msg)) {
|
||||
if (skynet_context_push(addr,&msg)) {
|
||||
skynet_error(NULL,"Drop local message from %u to %s",msg.source,name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
node->queue = NULL;
|
||||
}
|
||||
|
||||
_unlock();
|
||||
|
||||
if (queue) {
|
||||
skynet_mq_release(queue);
|
||||
}
|
||||
}
|
||||
|
||||
// Always in main harbor thread
|
||||
|
||||
static void
|
||||
_remote_harbor_update(int harbor_id, const char * addr) {
|
||||
struct remote * r = &Z->remote[harbor_id-1];
|
||||
void *socket = zmq_socket( Z->zmq_context, ZMQ_PUSH);
|
||||
int rc = zmq_connect(socket, addr);
|
||||
if (rc<0) {
|
||||
skynet_error(NULL, "Can't connect to %d %s",harbor_id,addr);
|
||||
zmq_close(socket);
|
||||
socket = NULL;
|
||||
}
|
||||
if (socket) {
|
||||
void *old_socket = r->socket;
|
||||
if (old_socket) {
|
||||
zmq_close(old_socket);
|
||||
}
|
||||
struct message_remote_queue * queue = r->queue;
|
||||
|
||||
if (queue) {
|
||||
struct skynet_remote_message msg;
|
||||
while (!skynet_remotemq_pop(queue, &msg)) {
|
||||
skynet_remotemq_push(Z->queue, &msg);
|
||||
}
|
||||
skynet_remotemq_release(queue);
|
||||
r->queue = NULL;
|
||||
}
|
||||
|
||||
r->socket = socket;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
_report_zmq_error(int rc) {
|
||||
if (rc) {
|
||||
fprintf(stderr, "zmq error : %s\n",zmq_strerror(errno));
|
||||
exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
_isdecimal(int c) {
|
||||
return c>='0' && c<='9';
|
||||
}
|
||||
|
||||
// Name-updating protocols:
|
||||
//
|
||||
// 1) harbor_id=harbor_address
|
||||
// 2) context_name=context_handle
|
||||
static int
|
||||
_split_name(uint8_t *buf, int len, int *np) {
|
||||
uint8_t *sep;
|
||||
if (len > 0 && _isdecimal(buf[0])) {
|
||||
int i=0;
|
||||
int n=0;
|
||||
do {
|
||||
n = n*10 + (buf[i]-'0');
|
||||
} while(++i<len && _isdecimal(buf[i]));
|
||||
if (i < len && buf[i] == '=') {
|
||||
buf[i] = '\0';
|
||||
*np = n;
|
||||
return i;
|
||||
}
|
||||
} else if ((sep = memchr(buf, '=', len)) != NULL) {
|
||||
*sep = '\0';
|
||||
return (int)(sep-buf);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Always in main harbor thread
|
||||
static void
|
||||
_name_update() {
|
||||
zmq_msg_t content;
|
||||
zmq_msg_init(&content);
|
||||
int rc = zmq_recv(Z->zmq_local,&content,0);
|
||||
_report_zmq_error(rc);
|
||||
int sz = zmq_msg_size(&content);
|
||||
uint8_t * buffer = zmq_msg_data(&content);
|
||||
|
||||
int n = 0;
|
||||
int i = _split_name(buffer, sz, &n);
|
||||
if (i == -1) {
|
||||
char tmp[sz+1];
|
||||
memcpy(tmp,buffer,sz);
|
||||
tmp[sz] = '\0';
|
||||
skynet_error(NULL, "Invalid master update [%s]",tmp);
|
||||
zmq_msg_close(&content);
|
||||
return;
|
||||
}
|
||||
|
||||
char tmp[sz-i];
|
||||
memcpy(tmp,buffer+i+1,sz-i-1);
|
||||
tmp[sz-i-1]='\0';
|
||||
|
||||
if (n>0 && n <= REMOTE_MAX) {
|
||||
_remote_harbor_update(n, tmp);
|
||||
} else {
|
||||
uint32_t source = strtoul(tmp,NULL,16);
|
||||
if (source == 0) {
|
||||
skynet_error(NULL, "Invalid master update [%s=%s]",(const char *)buffer,tmp);
|
||||
} else {
|
||||
_register_name((const char *)buffer, source);
|
||||
}
|
||||
}
|
||||
|
||||
zmq_msg_close(&content);
|
||||
}
|
||||
|
||||
// Always in main harbor thread
|
||||
static void
|
||||
remote_query_harbor(int harbor_id) {
|
||||
char tmp[32];
|
||||
int sz = sprintf(tmp,"%d",harbor_id);
|
||||
zmq_msg_t request;
|
||||
zmq_msg_init_size(&request,sz);
|
||||
memcpy(zmq_msg_data(&request),tmp,sz);
|
||||
zmq_send(Z->zmq_master_request, &request, 0);
|
||||
zmq_msg_close(&request);
|
||||
zmq_msg_t reply;
|
||||
zmq_msg_init(&reply);
|
||||
int rc = zmq_recv(Z->zmq_master_request, &reply, 0);
|
||||
_report_zmq_error(rc);
|
||||
sz = zmq_msg_size(&reply);
|
||||
char tmp2[sz+1];
|
||||
memcpy(tmp2,zmq_msg_data(&reply),sz);
|
||||
tmp2[sz] = '\0';
|
||||
_remote_harbor_update(harbor_id, tmp2);
|
||||
zmq_msg_close(&reply);
|
||||
}
|
||||
|
||||
// Always in main harbor thread
|
||||
static void
|
||||
_remote_register_name(const char *name, uint32_t source) {
|
||||
char tmp[strlen(name) + 20];
|
||||
int sz = sprintf(tmp,"%s=%X",name,source);
|
||||
zmq_msg_t msg;
|
||||
zmq_msg_init_size(&msg,sz);
|
||||
memcpy(zmq_msg_data(&msg), tmp , sz);
|
||||
zmq_send(Z->zmq_master_request, &msg,0);
|
||||
zmq_msg_close(&msg);
|
||||
zmq_msg_init(&msg);
|
||||
int rc = zmq_recv(Z->zmq_master_request, &msg,0);
|
||||
_report_zmq_error(rc);
|
||||
zmq_msg_close(&msg);
|
||||
}
|
||||
|
||||
// Always in main harbor thread
|
||||
static void
|
||||
_remote_query_name(const char *name) {
|
||||
int sz = strlen(name);
|
||||
zmq_msg_t msg;
|
||||
zmq_msg_init_size(&msg,sz);
|
||||
memcpy(zmq_msg_data(&msg), name , sz);
|
||||
zmq_send(Z->zmq_master_request, &msg,0);
|
||||
zmq_msg_close(&msg);
|
||||
zmq_msg_init(&msg);
|
||||
int rc = zmq_recv(Z->zmq_master_request, &msg,0);
|
||||
_report_zmq_error(rc);
|
||||
sz = zmq_msg_size(&msg);
|
||||
char tmp[sz+1];
|
||||
memcpy(tmp, zmq_msg_data(&msg),sz);
|
||||
tmp[sz] = '\0';
|
||||
|
||||
uint32_t addr = strtoul(tmp,NULL,16);
|
||||
_register_name(name,addr);
|
||||
|
||||
zmq_msg_close(&msg);
|
||||
}
|
||||
|
||||
// Always in main harbor thread
|
||||
static void
|
||||
free_message(void *data, void *hint) {
|
||||
free(data);
|
||||
}
|
||||
|
||||
static void
|
||||
remote_socket_send(void * socket, struct skynet_remote_message *msg) {
|
||||
struct remote_header rh;
|
||||
rh.source = msg->message.source;
|
||||
rh.destination = msg->destination;
|
||||
rh.session = msg->message.session;
|
||||
zmq_msg_t part;
|
||||
zmq_msg_init_size(&part,sizeof(struct remote_header));
|
||||
uint8_t * buffer = zmq_msg_data(&part);
|
||||
remote_header_to_buffer(&rh,buffer);
|
||||
zmq_send(socket, &part, ZMQ_SNDMORE);
|
||||
zmq_msg_close(&part);
|
||||
|
||||
zmq_msg_init_data(&part,msg->message.data,msg->message.sz,free_message,NULL);
|
||||
zmq_send(socket, &part, 0);
|
||||
zmq_msg_close(&part);
|
||||
}
|
||||
|
||||
// Always in main harbor thread
|
||||
|
||||
// remote message has two part
|
||||
// when part one is nil (size == 0), part two is name update
|
||||
// Or part one is source:destination (8 bytes little endian), part two is a binary block for message
|
||||
static void
|
||||
_remote_recv() {
|
||||
zmq_msg_t header;
|
||||
zmq_msg_init(&header);
|
||||
int rc = zmq_recv(Z->zmq_local,&header,0);
|
||||
_report_zmq_error(rc);
|
||||
size_t s = zmq_msg_size(&header);
|
||||
if (s!=sizeof(struct remote_header)) {
|
||||
// s should be 0
|
||||
if (s>0) {
|
||||
char tmp[s+1];
|
||||
memcpy(tmp, zmq_msg_data(&header),s);
|
||||
tmp[s] = '\0';
|
||||
skynet_error(NULL,"Invalid master header [%s]",tmp);
|
||||
}
|
||||
_name_update();
|
||||
return;
|
||||
}
|
||||
uint8_t * buffer = zmq_msg_data(&header);
|
||||
struct remote_header rh;
|
||||
buffer_to_remote_header(buffer, &rh);
|
||||
zmq_close(&header);
|
||||
|
||||
zmq_msg_t * data = malloc(sizeof(zmq_msg_t));
|
||||
zmq_msg_init(data);
|
||||
rc = zmq_recv(Z->zmq_local,data,0);
|
||||
_report_zmq_error(rc);
|
||||
|
||||
struct skynet_message msg;
|
||||
msg.session = (int)rh.session;
|
||||
msg.source = rh.source;
|
||||
msg.data = data;
|
||||
msg.sz = zmq_msg_size(data);
|
||||
|
||||
// push remote message to local message queue
|
||||
if (skynet_context_push(rh.destination, &msg)) {
|
||||
zmq_msg_close(data);
|
||||
free(data);
|
||||
skynet_error(NULL, "Drop remote message from %u to %u",rh.source, rh.destination);
|
||||
}
|
||||
}
|
||||
|
||||
// Always in main harbor thread
|
||||
static void
|
||||
_remote_send() {
|
||||
struct skynet_remote_message msg;
|
||||
while (!skynet_remotemq_pop(Z->queue,&msg)) {
|
||||
_goback:
|
||||
if (msg.destination == SKYNET_SYSTEM_NAME) {
|
||||
// register name
|
||||
char * name = msg.message.data;
|
||||
|
||||
if (msg.message.source) {
|
||||
_remote_register_name(name, msg.message.source);
|
||||
} else {
|
||||
_remote_query_name(name);
|
||||
}
|
||||
|
||||
free(name);
|
||||
} else {
|
||||
int harbor_id = (msg.destination >> HANDLE_REMOTE_SHIFT);
|
||||
assert(harbor_id > 0);
|
||||
struct remote * r = &Z->remote[harbor_id-1];
|
||||
if (r->socket == NULL) {
|
||||
if (r->queue == NULL) {
|
||||
r->queue = skynet_remotemq_create();
|
||||
skynet_remotemq_push(r->queue, &msg);
|
||||
remote_query_harbor(harbor_id);
|
||||
} else {
|
||||
skynet_remotemq_push(r->queue, &msg);
|
||||
}
|
||||
} else {
|
||||
remote_socket_send(r->socket, &msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
__sync_lock_release(&Z->notice_event);
|
||||
// double check
|
||||
if (!skynet_remotemq_pop(Z->queue,&msg)) {
|
||||
__sync_lock_test_and_set(&Z->notice_event, 1);
|
||||
goto _goback;
|
||||
}
|
||||
}
|
||||
|
||||
// Main harbor thread
|
||||
void *
|
||||
skynet_harbor_dispatch_thread(void *ud) {
|
||||
zmq_pollitem_t items[2];
|
||||
|
||||
items[0].socket = Z->zmq_queue_notice;
|
||||
items[0].events = ZMQ_POLLIN;
|
||||
items[1].socket = Z->zmq_local;
|
||||
items[1].events = ZMQ_POLLIN;
|
||||
|
||||
for (;;) {
|
||||
zmq_poll(items,2,-1);
|
||||
if (items[0].revents) {
|
||||
zmq_msg_t msg;
|
||||
zmq_msg_init(&msg);
|
||||
int rc = zmq_recv(Z->zmq_queue_notice,&msg,0);
|
||||
_report_zmq_error(rc);
|
||||
zmq_msg_close(&msg);
|
||||
_remote_send();
|
||||
}
|
||||
if (items[1].revents) {
|
||||
_remote_recv();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Call only at init
|
||||
static void
|
||||
register_harbor(void *request, const char *local, int harbor) {
|
||||
char tmp[1024];
|
||||
sprintf(tmp,"%d",harbor);
|
||||
size_t sz = strlen(tmp);
|
||||
|
||||
zmq_msg_t req;
|
||||
zmq_msg_init_size (&req , sz);
|
||||
memcpy(zmq_msg_data(&req),tmp,sz);
|
||||
zmq_send (request, &req, 0);
|
||||
zmq_msg_close (&req);
|
||||
|
||||
zmq_msg_t reply;
|
||||
zmq_msg_init (&reply);
|
||||
int rc = zmq_recv(request, &reply, 0);
|
||||
_report_zmq_error(rc);
|
||||
|
||||
sz = zmq_msg_size (&reply);
|
||||
if (sz > 0) {
|
||||
memcpy(tmp,zmq_msg_data(&reply),sz);
|
||||
tmp[sz] = '\0';
|
||||
fprintf(stderr, "Harbor %d is already registered by %s\n", harbor, tmp);
|
||||
exit(1);
|
||||
}
|
||||
zmq_msg_close (&reply);
|
||||
|
||||
sprintf(tmp,"%d=%s",harbor,local);
|
||||
sz = strlen(tmp);
|
||||
zmq_msg_init_size (&req , sz);
|
||||
memcpy(zmq_msg_data(&req),tmp,sz);
|
||||
zmq_send (request, &req, 0);
|
||||
zmq_msg_close (&req);
|
||||
|
||||
zmq_msg_init (&reply);
|
||||
rc = zmq_recv (request, &reply, 0);
|
||||
_report_zmq_error(rc);
|
||||
zmq_msg_close (&reply);
|
||||
}
|
||||
|
||||
void
|
||||
skynet_harbor_init(void * context, const char * master, const char *local, int harbor) {
|
||||
if (harbor <=0 || harbor>255 || strlen(local) > 512) {
|
||||
fprintf(stderr,"Invalid harbor id\n");
|
||||
exit(1);
|
||||
}
|
||||
void *request = zmq_socket (context, ZMQ_REQ);
|
||||
int r = zmq_connect(request, master);
|
||||
if (r<0) {
|
||||
fprintf(stderr, "Can't connect to master: %s\n",master);
|
||||
exit(1);
|
||||
}
|
||||
void *harbor_socket = zmq_socket(context, ZMQ_PULL);
|
||||
r = zmq_bind(harbor_socket, local);
|
||||
if (r<0) {
|
||||
fprintf(stderr, "Can't bind to local : %s\n",local);
|
||||
exit(1);
|
||||
}
|
||||
register_harbor(request,local, harbor);
|
||||
printf("Start harbor on : %s\n",local);
|
||||
|
||||
struct harbor * h = malloc(sizeof(*h));
|
||||
memset(h, 0, sizeof(*h));
|
||||
h->zmq_context = context;
|
||||
h->zmq_master_request = request;
|
||||
h->zmq_local = harbor_socket;
|
||||
h->map = _hash_new();
|
||||
h->harbor = harbor;
|
||||
h->queue = skynet_remotemq_create();
|
||||
h->zmq_queue_notice = zmq_socket(context, ZMQ_PULL);
|
||||
r = zmq_bind(h->zmq_queue_notice, "inproc://notice");
|
||||
assert(r==0);
|
||||
|
||||
Z = h;
|
||||
}
|
||||
|
||||
// thread safe api
|
||||
void *
|
||||
skynet_harbor_message_open(struct skynet_message * message) {
|
||||
return zmq_msg_data(message->data);
|
||||
}
|
||||
|
||||
void
|
||||
skynet_harbor_message_close(struct skynet_message * message) {
|
||||
zmq_msg_close(message->data);
|
||||
}
|
||||
|
||||
int
|
||||
skynet_harbor_message_isremote(uint32_t handle) {
|
||||
int harbor_id = handle >> HANDLE_REMOTE_SHIFT;
|
||||
return !(harbor_id == 0 || harbor_id == Z->harbor);
|
||||
}
|
||||
21
skynet-src/skynet_harbor.h
Normal file
21
skynet-src/skynet_harbor.h
Normal file
@@ -0,0 +1,21 @@
|
||||
#ifndef SKYNET_HARBOR_H
|
||||
#define SKYNET_HARBOR_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct skynet_message;
|
||||
|
||||
void skynet_harbor_send(const char *name, uint32_t destination, struct skynet_message * message);
|
||||
void skynet_harbor_register(const char *name, uint32_t handle);
|
||||
|
||||
// remote message is diffrent from local message.
|
||||
// We must use these api to open and close message , see skynet_server.c
|
||||
int skynet_harbor_message_isremote(uint32_t handle);
|
||||
void * skynet_harbor_message_open(struct skynet_message * message);
|
||||
void skynet_harbor_message_close(struct skynet_message * message);
|
||||
|
||||
// harbor worker thread
|
||||
void * skynet_harbor_dispatch_thread(void *ud);
|
||||
void skynet_harbor_init(void * context, const char * master, const char *local, int harbor);
|
||||
|
||||
#endif
|
||||
18
skynet-src/skynet_imp.h
Normal file
18
skynet-src/skynet_imp.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef SKYNET_IMP_H
|
||||
#define SKYNET_IMP_H
|
||||
|
||||
struct skynet_config {
|
||||
int thread;
|
||||
int mqueue_size;
|
||||
int harbor;
|
||||
const char * logger;
|
||||
const char * module_path;
|
||||
const char * master;
|
||||
const char * local;
|
||||
const char * start;
|
||||
int standalone;
|
||||
};
|
||||
|
||||
void skynet_start(struct skynet_config * config);
|
||||
|
||||
#endif
|
||||
52
skynet-src/skynet_logger.c
Normal file
52
skynet-src/skynet_logger.c
Normal file
@@ -0,0 +1,52 @@
|
||||
#include "skynet.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
struct logger {
|
||||
FILE * handle;
|
||||
int close;
|
||||
};
|
||||
|
||||
struct logger *
|
||||
logger_create(void) {
|
||||
struct logger * inst = malloc(sizeof(*inst));
|
||||
inst->handle = NULL;
|
||||
inst->close = 0;
|
||||
return inst;
|
||||
}
|
||||
|
||||
void
|
||||
logger_release(struct logger * inst) {
|
||||
if (inst->close) {
|
||||
fclose(inst->handle);
|
||||
}
|
||||
free(inst);
|
||||
}
|
||||
|
||||
static void
|
||||
_logger(struct skynet_context * context, void *ud, int session, const char * uid, const void * msg, size_t sz) {
|
||||
struct logger * inst = ud;
|
||||
fprintf(inst->handle, "[%s] ",uid);
|
||||
fwrite(msg, sz , 1, inst->handle);
|
||||
fprintf(inst->handle, "\n");
|
||||
}
|
||||
|
||||
int
|
||||
logger_init(struct logger * inst, struct skynet_context *ctx, const char * parm) {
|
||||
if (parm) {
|
||||
inst->handle = fopen(parm,"w");
|
||||
if (inst->handle == NULL) {
|
||||
return 1;
|
||||
}
|
||||
inst->close = 1;
|
||||
} else {
|
||||
inst->handle = stdout;
|
||||
}
|
||||
if (inst->handle) {
|
||||
skynet_callback(ctx, inst, _logger);
|
||||
skynet_command(ctx, "REG", ".logger");
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
117
skynet-src/skynet_main.c
Normal file
117
skynet-src/skynet_main.c
Normal file
@@ -0,0 +1,117 @@
|
||||
#include "skynet_imp.h"
|
||||
#include "skynet_env.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <lua.h>
|
||||
#include <lualib.h>
|
||||
#include <lauxlib.h>
|
||||
|
||||
static int
|
||||
optint(const char *key, int opt) {
|
||||
const char * str = skynet_getenv(key);
|
||||
if (str == NULL) {
|
||||
char tmp[20];
|
||||
sprintf(tmp,"%d",opt);
|
||||
skynet_setenv(key, tmp);
|
||||
return opt;
|
||||
}
|
||||
return strtol(str, NULL, 10);
|
||||
}
|
||||
|
||||
static int
|
||||
optboolean(const char *key, int opt) {
|
||||
const char * str = skynet_getenv(key);
|
||||
if (str == NULL) {
|
||||
skynet_setenv(key, opt ? "true" : "false");
|
||||
return opt;
|
||||
}
|
||||
return strcmp(str,"true")==0;
|
||||
}
|
||||
|
||||
static const char *
|
||||
optstring(const char *key,const char * opt) {
|
||||
const char * str = skynet_getenv(key);
|
||||
if (str == NULL) {
|
||||
if (opt) {
|
||||
skynet_setenv(key, opt);
|
||||
}
|
||||
return opt;
|
||||
}
|
||||
return str;
|
||||
}
|
||||
|
||||
static void
|
||||
_init_env(lua_State *L) {
|
||||
lua_rawgeti(L, LUA_REGISTRYINDEX, LUA_RIDX_GLOBALS);
|
||||
lua_pushnil(L); /* first key */
|
||||
while (lua_next(L, -2) != 0) {
|
||||
int keyt = lua_type(L, -2);
|
||||
if (keyt != LUA_TSTRING) {
|
||||
fprintf(stderr, "Invalid config table\n");
|
||||
exit(1);
|
||||
}
|
||||
const char * key = lua_tostring(L,-2);
|
||||
if (lua_type(L,-1) == LUA_TBOOLEAN) {
|
||||
int b = lua_toboolean(L,-1);
|
||||
skynet_setenv(key,b ? "true" : "false" );
|
||||
} else {
|
||||
const char * value = lua_tostring(L,-1);
|
||||
if (value == NULL) {
|
||||
fprintf(stderr, "Invalid config table key = %s\n", key);
|
||||
exit(1);
|
||||
}
|
||||
skynet_setenv(key,value);
|
||||
}
|
||||
lua_pop(L,1);
|
||||
}
|
||||
lua_pop(L,1);
|
||||
}
|
||||
|
||||
int
|
||||
main(int argc, char *argv[]) {
|
||||
const char * config_file = "config";
|
||||
if (argc > 1) {
|
||||
config_file = argv[1];
|
||||
}
|
||||
skynet_env_init();
|
||||
|
||||
struct skynet_config config;
|
||||
|
||||
struct lua_State *L = luaL_newstate();
|
||||
luaL_openlibs(L); // link lua lib
|
||||
lua_close(L);
|
||||
|
||||
L = luaL_newstate();
|
||||
|
||||
int err = luaL_dofile(L, config_file);
|
||||
if (err) {
|
||||
fprintf(stderr,"%s\n",lua_tostring(L,-1));
|
||||
lua_close(L);
|
||||
return 1;
|
||||
}
|
||||
_init_env(L);
|
||||
|
||||
const char *path = optstring("lua_path","./lualib/?.lua;./lualib/?/init.lua");
|
||||
setenv("LUA_PATH",path,1);
|
||||
const char *cpath = optstring("lua_cpath","./lualib/?.so");
|
||||
setenv("LUA_CPATH",cpath,1);
|
||||
optstring("luaservice","./service/?.lua");
|
||||
|
||||
config.thread = optint("thread",8);
|
||||
config.mqueue_size = optint("mqueue",256);
|
||||
config.module_path = optstring("cpath","./service/?.so");
|
||||
config.logger = optstring("logger",NULL);
|
||||
config.harbor = optint("harbor", 1);
|
||||
config.master = optstring("master","tcp://127.0.0.1:2012");
|
||||
config.start = optstring("start","main.lua");
|
||||
config.local = optstring("address","tcp://127.0.0.1:2525");
|
||||
config.standalone = optboolean("standalone",0);
|
||||
|
||||
lua_close(L);
|
||||
|
||||
skynet_start(&config);
|
||||
|
||||
return 0;
|
||||
}
|
||||
147
skynet-src/skynet_module.c
Normal file
147
skynet-src/skynet_module.c
Normal file
@@ -0,0 +1,147 @@
|
||||
#include "skynet_module.h"
|
||||
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <dlfcn.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define MAX_MODULE_TYPE 32
|
||||
|
||||
struct modules {
|
||||
int count;
|
||||
int lock;
|
||||
const char * path;
|
||||
struct skynet_module m[MAX_MODULE_TYPE];
|
||||
};
|
||||
|
||||
static struct modules * M = NULL;
|
||||
|
||||
static void *
|
||||
_try_open(struct modules *m, const char * name) {
|
||||
const char * path = m->path;
|
||||
size_t path_size = strlen(path);
|
||||
size_t name_size = strlen(name);
|
||||
|
||||
int sz = path_size + name_size;
|
||||
char tmp[sz];
|
||||
int i;
|
||||
for (i=0;path[i]!='?' && path[i]!='\0';i++) {
|
||||
tmp[i] = path[i];
|
||||
}
|
||||
memcpy(tmp+i,name,name_size);
|
||||
if (path[i] == '?') {
|
||||
strcpy(tmp+i+name_size,path+i+1);
|
||||
} else {
|
||||
fprintf(stderr,"Invalid C service path\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void * dl = dlopen(tmp, RTLD_NOW | RTLD_GLOBAL);
|
||||
|
||||
if (dl == NULL) {
|
||||
fprintf(stderr, "try open %s failed : %s\n",tmp,dlerror());
|
||||
}
|
||||
|
||||
return dl;
|
||||
}
|
||||
|
||||
static struct skynet_module *
|
||||
_query(const char * name) {
|
||||
int i;
|
||||
for (i=0;i<M->count;i++) {
|
||||
if (strcmp(M->m[i].name,name)==0) {
|
||||
return &M->m[i];
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static int
|
||||
_open_sym(struct skynet_module *mod) {
|
||||
size_t name_size = strlen(mod->name);
|
||||
char tmp[name_size + 9]; // create/init/release , longest name is release (7)
|
||||
memcpy(tmp, mod->name, name_size);
|
||||
strcpy(tmp+name_size, "_create");
|
||||
mod->create = dlsym(mod->module, tmp);
|
||||
strcpy(tmp+name_size, "_init");
|
||||
mod->init = dlsym(mod->module, tmp);
|
||||
strcpy(tmp+name_size, "_release");
|
||||
mod->release = dlsym(mod->module, tmp);
|
||||
|
||||
return mod->init == NULL;
|
||||
}
|
||||
|
||||
struct skynet_module *
|
||||
skynet_module_query(const char * name) {
|
||||
struct skynet_module * result = _query(name);
|
||||
if (result)
|
||||
return result;
|
||||
|
||||
while(__sync_lock_test_and_set(&M->lock,1)) {}
|
||||
|
||||
result = _query(name); // double check
|
||||
|
||||
if (result == NULL && M->count < MAX_MODULE_TYPE) {
|
||||
int index = M->count;
|
||||
void * dl = _try_open(M,name);
|
||||
if (dl) {
|
||||
M->m[index].name = name;
|
||||
M->m[index].module = dl;
|
||||
|
||||
if (_open_sym(&M->m[index]) == 0) {
|
||||
M->m[index].name = strdup(name);
|
||||
M->count ++;
|
||||
result = &M->m[index];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
__sync_lock_release(&M->lock);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
skynet_module_insert(struct skynet_module *mod) {
|
||||
while(__sync_lock_test_and_set(&M->lock,1)) {}
|
||||
|
||||
struct skynet_module * m = _query(mod->name);
|
||||
assert(m == NULL && M->count < MAX_MODULE_TYPE);
|
||||
int index = M->count;
|
||||
M->m[index] = *mod;
|
||||
++M->count;
|
||||
__sync_lock_release(&M->lock);
|
||||
}
|
||||
|
||||
void *
|
||||
skynet_module_instance_create(struct skynet_module *m) {
|
||||
if (m->create) {
|
||||
return m->create();
|
||||
} else {
|
||||
return (void *)(intptr_t)(~0);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
skynet_module_instance_init(struct skynet_module *m, void * inst, struct skynet_context *ctx, const char * parm) {
|
||||
return m->init(inst, ctx, parm);
|
||||
}
|
||||
|
||||
void
|
||||
skynet_module_instance_release(struct skynet_module *m, void *inst) {
|
||||
if (m->release) {
|
||||
m->release(inst);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
skynet_module_init(const char *path) {
|
||||
struct modules *m = malloc(sizeof(*m));
|
||||
m->count = 0;
|
||||
m->path = strdup(path);
|
||||
m->lock = 0;
|
||||
|
||||
M = m;
|
||||
}
|
||||
26
skynet-src/skynet_module.h
Normal file
26
skynet-src/skynet_module.h
Normal file
@@ -0,0 +1,26 @@
|
||||
#ifndef SKYNET_MODULE_H
|
||||
#define SKYNET_MODULE_H
|
||||
|
||||
struct skynet_context;
|
||||
|
||||
typedef void * (*skynet_dl_create)(void);
|
||||
typedef int (*skynet_dl_init)(void * inst, struct skynet_context *, const char * parm);
|
||||
typedef void (*skynet_dl_release)(void * inst);
|
||||
|
||||
struct skynet_module {
|
||||
const char * name;
|
||||
void * module;
|
||||
skynet_dl_create create;
|
||||
skynet_dl_init init;
|
||||
skynet_dl_release release;
|
||||
};
|
||||
|
||||
void skynet_module_insert(struct skynet_module *mod);
|
||||
struct skynet_module * skynet_module_query(const char * name);
|
||||
void * skynet_module_instance_create(struct skynet_module *);
|
||||
int skynet_module_instance_init(struct skynet_module *, void * inst, struct skynet_context *ctx, const char * parm);
|
||||
void skynet_module_instance_release(struct skynet_module *, void *inst);
|
||||
|
||||
void skynet_module_init(const char *path);
|
||||
|
||||
#endif
|
||||
237
skynet-src/skynet_mq.c
Normal file
237
skynet-src/skynet_mq.c
Normal file
@@ -0,0 +1,237 @@
|
||||
#include "skynet_mq.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
|
||||
#define DEFAULT_QUEUE_SIZE 64;
|
||||
|
||||
struct message_queue {
|
||||
uint32_t handle;
|
||||
int cap;
|
||||
int head;
|
||||
int tail;
|
||||
int lock;
|
||||
struct skynet_message *queue;
|
||||
};
|
||||
|
||||
struct global_queue {
|
||||
int cap;
|
||||
int head;
|
||||
int tail;
|
||||
int lock;
|
||||
struct message_queue ** queue;
|
||||
};
|
||||
|
||||
struct message_remote_queue {
|
||||
int cap;
|
||||
int head;
|
||||
int tail;
|
||||
int lock;
|
||||
struct skynet_remote_message *queue;
|
||||
};
|
||||
|
||||
static struct global_queue *Q = NULL;
|
||||
|
||||
static inline void
|
||||
_lock_global_queue() {
|
||||
while (__sync_lock_test_and_set(&Q->lock,1)) {}
|
||||
}
|
||||
|
||||
#define LOCK(q) while (__sync_lock_test_and_set(&(q)->lock,1)) {}
|
||||
#define UNLOCK(q) __sync_lock_release(&(q)->lock);
|
||||
|
||||
void
|
||||
skynet_globalmq_push(struct message_queue * queue) {
|
||||
struct global_queue *q= Q;
|
||||
LOCK(q)
|
||||
|
||||
q->queue[q->tail] = queue;
|
||||
if (++ q->tail >= q->cap) {
|
||||
q->tail = 0;
|
||||
}
|
||||
|
||||
if (q->head == q->tail) {
|
||||
struct message_queue **new_queue = malloc(sizeof(struct message_queue *) * q->cap * 2);
|
||||
int i;
|
||||
for (i=0;i<q->cap;i++) {
|
||||
new_queue[i] = q->queue[(q->head + i) % q->cap];
|
||||
}
|
||||
q->head = 0;
|
||||
q->tail = q->cap;
|
||||
q->cap *= 2;
|
||||
|
||||
free(q->queue);
|
||||
q->queue = new_queue;
|
||||
}
|
||||
|
||||
UNLOCK(q)
|
||||
}
|
||||
|
||||
struct message_queue *
|
||||
skynet_globalmq_pop() {
|
||||
struct global_queue *q = Q;
|
||||
struct message_queue * ret = NULL;
|
||||
LOCK(q)
|
||||
|
||||
if (q->head != q->tail) {
|
||||
ret = q->queue[q->head];
|
||||
if ( ++ q->head >= q->cap) {
|
||||
q->head = 0;
|
||||
}
|
||||
}
|
||||
|
||||
UNLOCK(q)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
struct message_queue *
|
||||
skynet_mq_create(uint32_t handle) {
|
||||
struct message_queue *q = malloc(sizeof(*q));
|
||||
q->handle = handle;
|
||||
q->cap = DEFAULT_QUEUE_SIZE;
|
||||
q->head = 0;
|
||||
q->tail = 0;
|
||||
q->lock = 0;
|
||||
q->queue = malloc(sizeof(struct skynet_message) * q->cap);
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
void
|
||||
skynet_mq_release(struct message_queue *q) {
|
||||
free(q->queue);
|
||||
free(q);
|
||||
}
|
||||
|
||||
uint32_t
|
||||
skynet_mq_handle(struct message_queue *q) {
|
||||
return q->handle;
|
||||
}
|
||||
|
||||
|
||||
int
|
||||
skynet_mq_pop(struct message_queue *q, struct skynet_message *message) {
|
||||
int ret = -1;
|
||||
LOCK(q)
|
||||
|
||||
if (q->head != q->tail) {
|
||||
*message = q->queue[q->head];
|
||||
ret = 0;
|
||||
if ( ++ q->head >= q->cap) {
|
||||
q->head = 0;
|
||||
}
|
||||
}
|
||||
|
||||
UNLOCK(q)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
skynet_mq_push(struct message_queue *q, struct skynet_message *message) {
|
||||
LOCK(q)
|
||||
|
||||
q->queue[q->tail] = *message;
|
||||
if (++ q->tail >= q->cap) {
|
||||
q->tail = 0;
|
||||
}
|
||||
|
||||
if (q->head == q->tail) {
|
||||
struct skynet_message *new_queue = malloc(sizeof(struct skynet_message) * q->cap * 2);
|
||||
int i;
|
||||
for (i=0;i<q->cap;i++) {
|
||||
new_queue[i] = q->queue[(q->head + i) % q->cap];
|
||||
}
|
||||
q->head = 0;
|
||||
q->tail = q->cap;
|
||||
q->cap *= 2;
|
||||
|
||||
free(q->queue);
|
||||
q->queue = new_queue;
|
||||
}
|
||||
|
||||
UNLOCK(q)
|
||||
}
|
||||
|
||||
void
|
||||
skynet_mq_init(int n) {
|
||||
struct global_queue *q = malloc(sizeof(*q));
|
||||
memset(q,0,sizeof(*q));
|
||||
int cap = 2;
|
||||
while (cap < n) {
|
||||
cap *=2;
|
||||
}
|
||||
|
||||
q->cap = cap;
|
||||
q->queue = malloc(cap * sizeof(struct skynet_message*));
|
||||
Q=q;
|
||||
}
|
||||
|
||||
// remote message queue
|
||||
|
||||
struct message_remote_queue *
|
||||
skynet_remotemq_create(void) {
|
||||
struct message_remote_queue *q = malloc(sizeof(*q));
|
||||
q->cap = DEFAULT_QUEUE_SIZE;
|
||||
q->head = 0;
|
||||
q->tail = 0;
|
||||
q->lock = 0;
|
||||
q->queue = malloc(sizeof(struct skynet_remote_message) * q->cap);
|
||||
|
||||
return q;
|
||||
}
|
||||
|
||||
void
|
||||
skynet_remotemq_release(struct message_remote_queue *q) {
|
||||
free(q->queue);
|
||||
free(q);
|
||||
}
|
||||
|
||||
int
|
||||
skynet_remotemq_pop(struct message_remote_queue *q, struct skynet_remote_message *message) {
|
||||
int ret = -1;
|
||||
LOCK(q)
|
||||
|
||||
if (q->head != q->tail) {
|
||||
*message = q->queue[q->head];
|
||||
ret = 0;
|
||||
if ( ++ q->head >= q->cap) {
|
||||
q->head = 0;
|
||||
}
|
||||
}
|
||||
|
||||
UNLOCK(q)
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void
|
||||
skynet_remotemq_push(struct message_remote_queue *q, struct skynet_remote_message *message) {
|
||||
assert(message->destination != 0);
|
||||
LOCK(q)
|
||||
|
||||
q->queue[q->tail] = *message;
|
||||
|
||||
if (++ q->tail >= q->cap) {
|
||||
q->tail = 0;
|
||||
}
|
||||
|
||||
if (q->head == q->tail) {
|
||||
struct skynet_remote_message *new_queue = malloc(sizeof(struct skynet_remote_message) * q->cap * 2);
|
||||
int i;
|
||||
for (i=0;i<q->cap;i++) {
|
||||
new_queue[i] = q->queue[(q->head + i) % q->cap];
|
||||
}
|
||||
q->head = 0;
|
||||
q->tail = q->cap;
|
||||
q->cap *= 2;
|
||||
|
||||
free(q->queue);
|
||||
q->queue = new_queue;
|
||||
}
|
||||
|
||||
UNLOCK(q)
|
||||
}
|
||||
42
skynet-src/skynet_mq.h
Normal file
42
skynet-src/skynet_mq.h
Normal file
@@ -0,0 +1,42 @@
|
||||
#ifndef SKYNET_MESSAGE_QUEUE_H
|
||||
#define SKYNET_MESSAGE_QUEUE_H
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
|
||||
struct skynet_message {
|
||||
uint32_t source;
|
||||
int session;
|
||||
void * data;
|
||||
size_t sz;
|
||||
};
|
||||
|
||||
struct message_queue;
|
||||
|
||||
void skynet_globalmq_push(struct message_queue *);
|
||||
struct message_queue * skynet_globalmq_pop(void);
|
||||
|
||||
struct message_queue * skynet_mq_create(uint32_t handle);
|
||||
void skynet_mq_release(struct message_queue *);
|
||||
uint32_t skynet_mq_handle(struct message_queue *);
|
||||
|
||||
// 0 for success
|
||||
int skynet_mq_pop(struct message_queue *q, struct skynet_message *message);
|
||||
void skynet_mq_push(struct message_queue *q, struct skynet_message *message);
|
||||
|
||||
struct skynet_remote_message {
|
||||
uint32_t destination;
|
||||
struct skynet_message message;
|
||||
};
|
||||
|
||||
struct message_remote_queue;
|
||||
|
||||
struct message_remote_queue * skynet_remotemq_create(void);
|
||||
void skynet_remotemq_release(struct message_remote_queue *);
|
||||
|
||||
int skynet_remotemq_pop(struct message_remote_queue *q, struct skynet_remote_message *message);
|
||||
void skynet_remotemq_push(struct message_remote_queue *q, struct skynet_remote_message *message);
|
||||
|
||||
void skynet_mq_init(int cap);
|
||||
|
||||
#endif
|
||||
443
skynet-src/skynet_server.c
Normal file
443
skynet-src/skynet_server.c
Normal file
@@ -0,0 +1,443 @@
|
||||
#include "skynet_server.h"
|
||||
#include "skynet_module.h"
|
||||
#include "skynet_handle.h"
|
||||
#include "skynet_mq.h"
|
||||
#include "skynet_timer.h"
|
||||
#include "skynet_harbor.h"
|
||||
#include "skynet_env.h"
|
||||
#include "skynet.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <assert.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
|
||||
#define BLACKHOLE "blackhole"
|
||||
#define DEFAULT_MESSAGE_QUEUE 16
|
||||
|
||||
struct skynet_context {
|
||||
void * instance;
|
||||
struct skynet_module * mod;
|
||||
uint32_t handle;
|
||||
int ref;
|
||||
char handle_name[10];
|
||||
char result[32];
|
||||
void * cb_ud;
|
||||
skynet_cb cb;
|
||||
int session_id;
|
||||
int in_global_queue;
|
||||
int init;
|
||||
uint32_t forward;
|
||||
char * forward_address;
|
||||
struct message_queue *queue;
|
||||
};
|
||||
|
||||
static void
|
||||
_id_to_hex(char * str, uint32_t id) {
|
||||
int i;
|
||||
static char hex[16] = { '0','1','2','3','4','5','6','7','8','9','A','B','C','D','E','F' };
|
||||
for (i=0;i<8;i++) {
|
||||
str[i] = hex[(id >> ((7-i) * 4))&0xf];
|
||||
}
|
||||
str[8] = '\0';
|
||||
}
|
||||
|
||||
struct skynet_context *
|
||||
skynet_context_new(const char * name, const char *param) {
|
||||
struct skynet_module * mod = skynet_module_query(name);
|
||||
|
||||
if (mod == NULL)
|
||||
return NULL;
|
||||
|
||||
void *inst = skynet_module_instance_create(mod);
|
||||
if (inst == NULL)
|
||||
return NULL;
|
||||
struct skynet_context * ctx = malloc(sizeof(*ctx));
|
||||
ctx->mod = mod;
|
||||
ctx->instance = inst;
|
||||
ctx->ref = 2;
|
||||
ctx->cb = NULL;
|
||||
ctx->cb_ud = NULL;
|
||||
// a trick, global loop can't be dispatch in init process
|
||||
ctx->in_global_queue = 1;
|
||||
|
||||
ctx->forward = 0;
|
||||
ctx->forward_address = NULL;
|
||||
ctx->session_id = 0;
|
||||
ctx->init = 0;
|
||||
ctx->handle = skynet_handle_register(ctx);
|
||||
char * uid = ctx->handle_name;
|
||||
uid[0] = ':';
|
||||
_id_to_hex(uid+1, ctx->handle);
|
||||
struct message_queue * queue = ctx->queue = skynet_mq_create(ctx->handle);
|
||||
// init function maybe use ctx->handle, so it must init at last
|
||||
|
||||
int r = skynet_module_instance_init(mod, inst, ctx, param);
|
||||
if (r == 0) {
|
||||
struct skynet_context * ret = skynet_context_release(ctx);
|
||||
if (ret) {
|
||||
ctx->init = 1;
|
||||
skynet_globalmq_push(ctx->queue);
|
||||
return ret;
|
||||
} else {
|
||||
// because of ctx->in_global_queue == 1 , so we should release queue here.
|
||||
skynet_mq_release(queue);
|
||||
}
|
||||
return NULL;
|
||||
} else {
|
||||
ctx->in_global_queue = 0;
|
||||
skynet_context_release(ctx);
|
||||
skynet_handle_retire(ctx->handle);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
skynet_context_newsession(struct skynet_context *ctx) {
|
||||
int session = ++ctx->session_id;
|
||||
if (session < 0) {
|
||||
ctx->session_id = 1;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return session;
|
||||
}
|
||||
|
||||
void
|
||||
skynet_context_grab(struct skynet_context *ctx) {
|
||||
__sync_add_and_fetch(&ctx->ref,1);
|
||||
}
|
||||
|
||||
static void
|
||||
_delete_context(struct skynet_context *ctx) {
|
||||
skynet_module_instance_release(ctx->mod, ctx->instance);
|
||||
if (!ctx->in_global_queue) {
|
||||
skynet_mq_release(ctx->queue);
|
||||
}
|
||||
free(ctx);
|
||||
}
|
||||
|
||||
struct skynet_context *
|
||||
skynet_context_release(struct skynet_context *ctx) {
|
||||
if (__sync_sub_and_fetch(&ctx->ref,1) == 0) {
|
||||
_delete_context(ctx);
|
||||
return NULL;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
||||
static int
|
||||
_forwarding(struct skynet_context *ctx, struct skynet_message *msg) {
|
||||
if (ctx->forward) {
|
||||
uint32_t des = ctx->forward;
|
||||
ctx->forward = 0;
|
||||
if (skynet_harbor_message_isremote(des)) {
|
||||
skynet_harbor_send(NULL, des, msg);
|
||||
} else {
|
||||
if (skynet_context_push(des, msg)) {
|
||||
free(msg->data);
|
||||
skynet_error(NULL, "Drop message from %x forward to %x (size=%d)", msg->source, des, (int)msg->sz);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
if (ctx->forward_address) {
|
||||
skynet_harbor_send(ctx->forward_address, 0, msg);
|
||||
free(ctx->forward_address);
|
||||
ctx->forward_address = NULL;
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
_dispatch_message(struct skynet_context *ctx, struct skynet_message *msg) {
|
||||
assert(ctx->init);
|
||||
if (msg->source == SKYNET_SYSTEM_TIMER) {
|
||||
ctx->cb(ctx, ctx->cb_ud, msg->session, NULL, msg->data, msg->sz);
|
||||
} else {
|
||||
char tmp[10];
|
||||
tmp[0] = ':';
|
||||
int not_delete;
|
||||
_id_to_hex(tmp+1, msg->source);
|
||||
if (skynet_harbor_message_isremote(msg->source)) {
|
||||
void * data = skynet_harbor_message_open(msg);
|
||||
ctx->cb(ctx, ctx->cb_ud, msg->session, tmp, data, msg->sz);
|
||||
not_delete = _forwarding(ctx, msg);
|
||||
if (!not_delete) {
|
||||
skynet_harbor_message_close(msg);
|
||||
}
|
||||
} else {
|
||||
ctx->cb(ctx, ctx->cb_ud, msg->session, tmp, msg->data, msg->sz);
|
||||
not_delete = _forwarding(ctx, msg);
|
||||
}
|
||||
if (!not_delete) {
|
||||
free(msg->data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int
|
||||
_drop_queue(struct message_queue *q) {
|
||||
// todo: send message back to message source
|
||||
struct skynet_message msg;
|
||||
int s = 0;
|
||||
while(!skynet_mq_pop(q, &msg)) {
|
||||
++s;
|
||||
if (skynet_harbor_message_isremote(msg.source)) {
|
||||
skynet_harbor_message_close(&msg);
|
||||
}
|
||||
free(msg.data);
|
||||
}
|
||||
skynet_mq_release(q);
|
||||
return s;
|
||||
}
|
||||
|
||||
int
|
||||
skynet_context_message_dispatch(void) {
|
||||
struct message_queue * q = skynet_globalmq_pop();
|
||||
if (q==NULL)
|
||||
return 1;
|
||||
|
||||
uint32_t handle = skynet_mq_handle(q);
|
||||
|
||||
struct skynet_context * ctx = skynet_handle_grab(handle);
|
||||
if (ctx == NULL) {
|
||||
int s = _drop_queue(q);
|
||||
if (s>0) {
|
||||
skynet_error(NULL, "Drop message queue %x (%d messages)", handle,s);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
assert(ctx->in_global_queue);
|
||||
|
||||
int re_q = 1;
|
||||
struct skynet_message msg;
|
||||
if (skynet_mq_pop(q,&msg)) {
|
||||
// empty queue
|
||||
__sync_lock_release(&ctx->in_global_queue);
|
||||
if (skynet_mq_pop(q,&msg)) {
|
||||
skynet_context_release(ctx);
|
||||
return 0;
|
||||
}
|
||||
if (__sync_lock_test_and_set(&ctx->in_global_queue, 1)) {
|
||||
re_q = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (ctx->cb == NULL) {
|
||||
if (skynet_harbor_message_isremote(msg.source)) {
|
||||
skynet_harbor_message_close(&msg);
|
||||
}
|
||||
free(msg.data);
|
||||
skynet_error(NULL, "Drop message from %x to %x without callback , size = %d",msg.source, handle, (int)msg.sz);
|
||||
} else {
|
||||
_dispatch_message(ctx, &msg);
|
||||
}
|
||||
|
||||
skynet_context_release(ctx);
|
||||
|
||||
if (re_q) {
|
||||
skynet_globalmq_push(q);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
const char *
|
||||
skynet_command(struct skynet_context * context, const char * cmd , const char * param) {
|
||||
if (strcmp(cmd,"TIMEOUT") == 0) {
|
||||
char * session_ptr = NULL;
|
||||
int ti = strtol(param, &session_ptr, 10);
|
||||
int session = skynet_context_newsession(context);
|
||||
if (session < 0)
|
||||
return NULL;
|
||||
skynet_timeout(context->handle, ti, session);
|
||||
sprintf(context->result, "%d", session);
|
||||
return context->result;
|
||||
}
|
||||
|
||||
if (strcmp(cmd,"NOW") == 0) {
|
||||
uint32_t ti = skynet_gettime();
|
||||
sprintf(context->result,"%u",ti);
|
||||
return context->result;
|
||||
}
|
||||
|
||||
if (strcmp(cmd,"REG") == 0) {
|
||||
if (param == NULL || param[0] == '\0') {
|
||||
return context->handle_name;
|
||||
} else if (param[0] == '.') {
|
||||
return skynet_handle_namehandle(context->handle, param + 1);
|
||||
} else {
|
||||
assert(context->handle!=0);
|
||||
skynet_harbor_register(param, context->handle);
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(cmd,"EXIT") == 0) {
|
||||
skynet_handle_retire(context->handle);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strcmp(cmd,"KILL") == 0) {
|
||||
uint32_t handle = 0;
|
||||
if (param[0] == ':') {
|
||||
handle = strtoul(param+1, NULL, 16);
|
||||
} else if (param[0] == '.') {
|
||||
handle = skynet_handle_findname(param+1);
|
||||
} else {
|
||||
// todo : kill global service
|
||||
}
|
||||
if (handle) {
|
||||
skynet_handle_retire(handle);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (strcmp(cmd,"LAUNCH") == 0) {
|
||||
size_t sz = strlen(param);
|
||||
char tmp[sz+1];
|
||||
strcpy(tmp,param);
|
||||
char * args = tmp;
|
||||
char * mod = strsep(&args, " \t\r\n");
|
||||
args = strsep(&args, "\r\n");
|
||||
struct skynet_context * inst = skynet_context_new(mod,args);
|
||||
if (inst == NULL) {
|
||||
fprintf(stderr, "Launch %s %s failed\n",mod,args);
|
||||
return NULL;
|
||||
} else {
|
||||
context->result[0] = ':';
|
||||
_id_to_hex(context->result+1, inst->handle);
|
||||
return context->result;
|
||||
}
|
||||
}
|
||||
|
||||
if (strcmp(cmd,"GETENV") == 0) {
|
||||
return skynet_getenv(param);
|
||||
}
|
||||
|
||||
if (strcmp(cmd,"SETENV") == 0) {
|
||||
size_t sz = strlen(param);
|
||||
char key[sz+1];
|
||||
int i;
|
||||
for (i=0;param[i] == ' ';i++) {
|
||||
key[i] = param[i];
|
||||
break;
|
||||
}
|
||||
key[i] = '\0';
|
||||
param += i+1;
|
||||
|
||||
skynet_setenv(key,param);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
skynet_forward(struct skynet_context * context, const char * addr) {
|
||||
uint32_t des = 0;
|
||||
assert(context->forward == 0 && context->forward_address == NULL);
|
||||
if (addr[0] == ':') {
|
||||
des = strtol(addr+1, NULL, 16);
|
||||
assert(des != 0);
|
||||
} else if (addr[0] == '.') {
|
||||
des = skynet_handle_findname(addr + 1);
|
||||
if (des == 0) {
|
||||
skynet_error(context, "Drop message forward %s", addr);
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
context->forward_address = strdup(addr);
|
||||
return;
|
||||
}
|
||||
context->forward = des;
|
||||
}
|
||||
|
||||
int
|
||||
skynet_send(struct skynet_context * context, const char * addr , int session, void * data, size_t sz, int flags) {
|
||||
char * msg;
|
||||
if ((flags & DONTCOPY) || data == NULL) {
|
||||
msg = data;
|
||||
} else {
|
||||
msg = malloc(sz+1);
|
||||
memcpy(msg, data, sz);
|
||||
msg[sz] = '\0';
|
||||
}
|
||||
int session_id = session;
|
||||
if (session < 0) {
|
||||
session = skynet_context_newsession(context);
|
||||
session_id = - session;
|
||||
}
|
||||
uint32_t des = 0;
|
||||
if (addr[0] == ':') {
|
||||
des = strtol(addr+1, NULL, 16);
|
||||
} else if (addr[0] == '.') {
|
||||
des = skynet_handle_findname(addr + 1);
|
||||
if (des == 0) {
|
||||
free(msg);
|
||||
skynet_error(context, "Drop message to %s, size = %d", addr, (int)sz);
|
||||
return session;
|
||||
}
|
||||
} else {
|
||||
struct skynet_message smsg;
|
||||
smsg.source = context->handle;
|
||||
smsg.session = session_id;
|
||||
smsg.data = msg;
|
||||
smsg.sz = sz;
|
||||
skynet_harbor_send(addr, 0, &smsg);
|
||||
return session;
|
||||
}
|
||||
|
||||
assert(des > 0);
|
||||
|
||||
struct skynet_message smsg;
|
||||
smsg.source = context->handle;
|
||||
smsg.session = session_id;
|
||||
smsg.data = msg;
|
||||
smsg.sz = sz;
|
||||
|
||||
if (skynet_harbor_message_isremote(des)) {
|
||||
skynet_harbor_send(NULL, des, &smsg);
|
||||
} else if (skynet_context_push(des, &smsg)) {
|
||||
free(msg);
|
||||
skynet_error(NULL, "Drop message from %x to %s (size=%d)", smsg.source, addr, (int)sz);
|
||||
return -1;
|
||||
}
|
||||
return session;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
skynet_context_handle(struct skynet_context *ctx) {
|
||||
return ctx->handle;
|
||||
}
|
||||
|
||||
void
|
||||
skynet_context_init(struct skynet_context *ctx, uint32_t handle) {
|
||||
ctx->handle = handle;
|
||||
}
|
||||
|
||||
void
|
||||
skynet_callback(struct skynet_context * context, void *ud, skynet_cb cb) {
|
||||
assert(context->cb == NULL);
|
||||
context->cb = cb;
|
||||
context->cb_ud = ud;
|
||||
}
|
||||
|
||||
int
|
||||
skynet_context_push(uint32_t handle, struct skynet_message *message) {
|
||||
struct skynet_context * ctx = skynet_handle_grab(handle);
|
||||
if (ctx == NULL) {
|
||||
return -1;
|
||||
}
|
||||
skynet_mq_push(ctx->queue, message);
|
||||
if (__sync_lock_test_and_set(&ctx->in_global_queue,1) == 0) {
|
||||
skynet_globalmq_push(ctx->queue);
|
||||
}
|
||||
skynet_context_release(ctx);
|
||||
|
||||
return 0;
|
||||
}
|
||||
18
skynet-src/skynet_server.h
Normal file
18
skynet-src/skynet_server.h
Normal file
@@ -0,0 +1,18 @@
|
||||
#ifndef SKYNET_SERVER_H
|
||||
#define SKYNET_SERVER_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
struct skynet_context;
|
||||
struct skynet_message;
|
||||
|
||||
struct skynet_context * skynet_context_new(const char * name, const char * parm);
|
||||
void skynet_context_grab(struct skynet_context *);
|
||||
struct skynet_context * skynet_context_release(struct skynet_context *);
|
||||
uint32_t skynet_context_handle(struct skynet_context *);
|
||||
void skynet_context_init(struct skynet_context *, uint32_t handle);
|
||||
int skynet_context_push(uint32_t handle, struct skynet_message *message);
|
||||
int skynet_context_newsession(struct skynet_context *);
|
||||
int skynet_context_message_dispatch(void); // return 1 when block
|
||||
|
||||
#endif
|
||||
92
skynet-src/skynet_start.c
Normal file
92
skynet-src/skynet_start.c
Normal file
@@ -0,0 +1,92 @@
|
||||
#include "skynet_server.h"
|
||||
#include "skynet_imp.h"
|
||||
#include "skynet_mq.h"
|
||||
#include "skynet_handle.h"
|
||||
#include "skynet_module.h"
|
||||
#include "skynet_timer.h"
|
||||
#include "skynet_harbor.h"
|
||||
#include "skynet_master.h"
|
||||
|
||||
#include <pthread.h>
|
||||
#include <unistd.h>
|
||||
#include <assert.h>
|
||||
#include <zmq.h>
|
||||
|
||||
static void *
|
||||
_timer(void *p) {
|
||||
for (;;) {
|
||||
skynet_updatetime();
|
||||
usleep(2500);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *
|
||||
_worker(void *p) {
|
||||
for (;;) {
|
||||
if (skynet_context_message_dispatch()) {
|
||||
usleep(1000);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
_start(int thread) {
|
||||
pthread_t pid[thread+2];
|
||||
|
||||
pthread_create(&pid[0], NULL, _timer, NULL);
|
||||
pthread_create(&pid[1], NULL, skynet_harbor_dispatch_thread, NULL);
|
||||
|
||||
int i;
|
||||
for (i=2;i<thread+2;i++) {
|
||||
pthread_create(&pid[i], NULL, _worker, NULL);
|
||||
}
|
||||
|
||||
for (i=0;i<thread+2;i++) {
|
||||
pthread_join(pid[i], NULL);
|
||||
}
|
||||
}
|
||||
|
||||
struct master_arg {
|
||||
void * context;
|
||||
const char * port;
|
||||
};
|
||||
|
||||
static void *
|
||||
_master_thread(void *ud) {
|
||||
struct master_arg * args = ud;
|
||||
skynet_master(args->context, args->port);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void
|
||||
_start_master(void * context, const char * port) {
|
||||
pthread_t pid;
|
||||
struct master_arg args;
|
||||
args.context = context;
|
||||
args.port = port;
|
||||
pthread_create(&pid, NULL, _master_thread, &args);
|
||||
}
|
||||
|
||||
void
|
||||
skynet_start(struct skynet_config * config) {
|
||||
void *context = zmq_init (1);
|
||||
assert(context);
|
||||
if (config->standalone) {
|
||||
_start_master(context, config->master);
|
||||
}
|
||||
// harbor must be init first
|
||||
skynet_harbor_init(context, config->master , config->local, config->harbor);
|
||||
skynet_handle_init(config->harbor);
|
||||
skynet_mq_init(config->mqueue_size);
|
||||
skynet_module_init(config->module_path);
|
||||
skynet_timer_init();
|
||||
struct skynet_context *ctx;
|
||||
ctx = skynet_context_new("logger", config->logger);
|
||||
assert(ctx);
|
||||
ctx = skynet_context_new("snlua", config->start);
|
||||
|
||||
_start(config->thread);
|
||||
}
|
||||
|
||||
8
skynet-src/skynet_system.h
Normal file
8
skynet-src/skynet_system.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#ifndef SKYNET_MESSAGE_SYSTEM_H
|
||||
#define SKYNET_MESSAGE_SYSTEM_H
|
||||
|
||||
#define SKYNET_SYSTEM_TIMER 1
|
||||
#define SKYNET_SYSTEM_LOGGER 2
|
||||
#define SKYNET_SYSTEM_NAME 3
|
||||
|
||||
#endif
|
||||
229
skynet-src/skynet_timer.c
Normal file
229
skynet-src/skynet_timer.c
Normal file
@@ -0,0 +1,229 @@
|
||||
#include "skynet_timer.h"
|
||||
#include "skynet_mq.h"
|
||||
#include "skynet_server.h"
|
||||
#include "skynet_handle.h"
|
||||
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.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;
|
||||
int 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-1];
|
||||
int lock;
|
||||
int time;
|
||||
uint32_t current;
|
||||
};
|
||||
|
||||
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)
|
||||
{
|
||||
int time=node->expire;
|
||||
int 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;
|
||||
int 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)-1],node);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
timer_add(struct timer *T,void *arg,size_t sz,int time)
|
||||
{
|
||||
struct timer_node *node = (struct timer_node *)malloc(sizeof(*node)+sz);
|
||||
memcpy(node+1,arg,sz);
|
||||
|
||||
while (__sync_lock_test_and_set(&T->lock,1)) {};
|
||||
|
||||
node->expire=time+T->time;
|
||||
add_node(T,node);
|
||||
|
||||
__sync_lock_release(&T->lock);
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
static struct timer *
|
||||
timer_create_timer()
|
||||
{
|
||||
struct timer *r=(struct timer *)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-1;j++) {
|
||||
link_clear(&r->t[i][j]);
|
||||
}
|
||||
}
|
||||
|
||||
r->lock = 0;
|
||||
r->current = 0;
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
static uint32_t
|
||||
_gettime(void) {
|
||||
struct timespec ti;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ti);
|
||||
uint32_t t = (uint32_t)(ti.tv_sec & 0xffffff) * 100;
|
||||
t += ti.tv_nsec / 10000000;
|
||||
|
||||
return t;
|
||||
}
|
||||
|
||||
void
|
||||
skynet_updatetime(void) {
|
||||
uint32_t ct = _gettime();
|
||||
if (ct > TI->current) {
|
||||
int diff = ct-TI->current;
|
||||
TI->current = ct;
|
||||
int i;
|
||||
for (i=0;i<diff;i++) {
|
||||
timer_execute(TI);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t
|
||||
skynet_gettime(void) {
|
||||
return TI->current;
|
||||
}
|
||||
|
||||
void
|
||||
skynet_timer_init(void) {
|
||||
TI = timer_create_timer();
|
||||
TI->current = _gettime();
|
||||
}
|
||||
14
skynet-src/skynet_timer.h
Normal file
14
skynet-src/skynet_timer.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#ifndef SKYNET_TIMER_H
|
||||
#define SKYNET_TIMER_H
|
||||
|
||||
#include "skynet_system.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
int skynet_timeout(uint32_t handle, int time, int session);
|
||||
void skynet_updatetime(void);
|
||||
uint32_t skynet_gettime(void);
|
||||
|
||||
void skynet_timer_init(void);
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user