#include "skynet.h" #include "skynet_handle.h" #include "skynet_server.h" #include "rwlock.h" #include #include #include #define DEFAULT_SLOT_SIZE 4 #define MAX_SLOT_SIZE 0x40000000 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; uint32_t handle = s->handle_index; for (i=0;islot_size;i++,handle++) { if (handle > HANDLE_MASK) { // 0 is reserved handle = 1; } 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; return handle; } } assert((s->slot_size*2 - 1) <= HANDLE_MASK); struct skynet_context ** new_slot = skynet_malloc(s->slot_size * 2 * sizeof(struct skynet_context *)); memset(new_slot, 0, s->slot_size * 2 * sizeof(struct skynet_context *)); for (i=0;islot_size;i++) { if (s->slot[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]; } } skynet_free(s->slot); s->slot = new_slot; s->slot_size *= 2; } } int skynet_handle_retire(uint32_t handle) { int ret = 0; 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 (ctx != NULL && skynet_context_handle(ctx) == handle) { s->slot[hash] = NULL; ret = 1; int i; int j=0, n=s->name_count; for (i=0; iname[i].handle == handle) { skynet_free(s->name[i].name); continue; } else if (i!=j) { s->name[j] = s->name[i]; } ++j; } s->name_count = j; } else { ctx = NULL; } rwlock_wunlock(&s->lock); if (ctx) { // release ctx may call skynet_handle_* , so wunlock first. skynet_context_release(ctx); } return ret; } void skynet_handle_retireall() { struct handle_storage *s = H; for (;;) { int n=0; int i; for (i=0;islot_size;i++) { rwlock_rlock(&s->lock); struct skynet_context * ctx = s->slot[i]; uint32_t handle = 0; if (ctx) { handle = skynet_context_handle(ctx); ++n; } rwlock_runlock(&s->lock); if (handle != 0) { skynet_handle_retire(handle); } } if (n==0) return; } } 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; assert(s->name_cap <= MAX_SLOT_SIZE); struct handle_name * n = skynet_malloc(s->name_cap * sizeof(struct handle_name)); int i; for (i=0;iname[i]; } for (i=before;iname_count;i++) { n[i+1] = s->name[i]; } skynet_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 = skynet_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 = skynet_malloc(sizeof(*H)); s->slot_size = DEFAULT_SLOT_SIZE; s->slot = skynet_malloc(s->slot_size * sizeof(struct skynet_context *)); memset(s->slot, 0, s->slot_size * sizeof(struct skynet_context *)); 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 = skynet_malloc(s->name_cap * sizeof(struct handle_name)); H = s; // Don't need to free H }