// 收回handle void skynet_handle_retire(uint32_t handle) { struct handle_storage *s = H; rwlock_wlock(&s->lock); uint32_t hash = handle & (s->slot_size-1); // 等价于 handle % s->slot_size struct skynet_context * ctx = s->slot[hash]; if (ctx != NULL && skynet_context_handle(ctx) == handle) { skynet_context_release(ctx); // free skynet_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) { // 在 name 表中 找到 handle 对应的 name free掉 free(s->name[i].name); continue; } else if (i!=j) { // 说明free了一个name s->name[j] = s->name[i]; // 因此需要将后续元素移到前面 } ++j; } s->name_count = j; } rwlock_wunlock(&s->lock); }
int skynet_multicast_castgroup(struct skynet_context * from, struct skynet_multicast_group * group, struct skynet_multicast_message *msg) { combine_queue(from, group); int release = 0; if (group->number > 0) { uint32_t source = skynet_context_handle(from); skynet_multicast_copy(msg, group->number); int i; for (i=0;i<group->number;i++) { uint32_t p = group->data[i]; struct skynet_context * ctx = skynet_handle_grab(p); if (ctx) { skynet_context_send(ctx, msg, 0 , source, PTYPE_MULTICAST , 0); skynet_context_release(ctx); } else { skynet_multicast_leavegroup(group, p); ++release; } } } skynet_multicast_copy(msg, -release); return group->number - release; }
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 (ctx != NULL && 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); }
int skynet_multicast_castgroup(struct skynet_context * from, struct skynet_multicast_group * group, struct skynet_multicast_message *msg) { combine_queue(from, group); if (group->number == 0) { skynet_multicast_dispatch(msg, NULL, NULL); return 0; } uint32_t source = skynet_context_handle(from); skynet_multicast_copy(msg, group->number); int i; int release = 0; for (i=0;i<group->number;i++) { struct pair * p = &group->data[i]; skynet_context_send(p->ctx, msg, 0 , source, PTYPE_MULTICAST , 0); int ref = skynet_context_ref(p->ctx); if (ref == 1) { skynet_context_release(p->ctx); struct skynet_context * ctx = skynet_handle_grab(p->handle); if (ctx == NULL) { p->ctx = NULL; skynet_multicast_leavegroup(group, p->handle); ++release; } } } return group->number - release; }
void skynet_harbor_exit() { struct skynet_context * ctx = REMOTE; REMOTE = NULL; if (ctx) { skynet_context_release(ctx); } }
void skynet_multicast_deletegroup(struct skynet_multicast_group * g) { int i; for (i=0;i<g->number;i++) { if (g->data[i].ctx) { skynet_context_release(g->data[i].ctx); } } free(g->data); free(g->enter_queue.data); free(g->leave_queue.data); free(g); }
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 // 1. 判断是否在同一个节点 // 2. 确认 handle 是没有超出 slot_size 的, 因为可能 slot_size = 8, handle = 15, skynet_context_handle(ctx) = 7 // 3. 其他线程没有修改 ctx && skynet_context_handle(ctx) == handle) { s->slot[hash] = NULL; ret = 1; // 将关联注册的名字资源也一同释放掉 int i; int j = 0, n = s->name_count; for (i = 0; i < n; ++i) { if (s->name[i].handle == handle) { // 判断是否有注册名字 skynet_free(s->name[i].name); // 释放内存 continue; // 一个 handle 允许注册多个名字, 继续判断 } else if (i != j) { // 向数组的头部移动 s->name[j] = s->name[i]; } ++j; } // 更新当前注册了名字的 context 数量 s->name_count = j; } else { ctx = NULL; } rwlock_wunlock(&s->lock); if (ctx) { // release ctx may call skynet_handle_* , so wunlock first. // 释放 ctx 可能会调用到 skynet_handle_* 方法, 所以先解 [写] 锁 skynet_context_release(ctx); } return ret; }
void skynet_multicast_cast(struct skynet_context * from, struct skynet_multicast_message *msg, const uint32_t *dests, int n) { uint32_t source = skynet_context_handle(from); skynet_multicast_copy(msg, n); if (n == 0) return; int i; int release = 0; for (i=0;i<n;i++) { uint32_t p = dests[i]; struct skynet_context * ctx = skynet_handle_grab(p); if (ctx) { skynet_context_send(ctx, msg, 0 , source, PTYPE_MULTICAST , 0); skynet_context_release(ctx); } else { ++release; } } skynet_multicast_copy(msg, -release); }
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; i<n; ++i) { if (s->name[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; }
static void combine_queue(struct skynet_context * from, struct skynet_multicast_group * group) { qsort(group->enter_queue.data, group->enter_queue.number, sizeof(uint32_t), compar_uint); qsort(group->leave_queue.data, group->leave_queue.number, sizeof(uint32_t), compar_uint); int i; int enter = group->enter_queue.number; uint32_t last = 0; int new_size = group->number + enter; if (new_size > group->cap) { group->data = realloc(group->data, new_size * sizeof(struct pair)); group->cap = new_size; } // combine enter queue int old_index = group->number - 1; int new_index = new_size - 1; for (i= enter - 1;i >=0 ; i--) { uint32_t handle = group->enter_queue.data[i]; if (handle == last) continue; last = handle; struct skynet_context * ctx = skynet_handle_grab(handle); if (ctx == NULL) continue; if (old_index < 0) { group->data[new_index].handle = handle; group->data[new_index].ctx = ctx; } else { struct pair * p = &group->data[old_index]; if (handle == p->handle) continue; if (handle > p->handle) { group->data[new_index].handle = handle; group->data[new_index].ctx = ctx; } else { group->data[new_index] = group->data[old_index]; --old_index; last = 0; ++i; } } --new_index; } while (old_index >= 0) { group->data[new_index] = group->data[old_index]; --old_index; --new_index; } group->enter_queue.number = 0; // remove leave queue old_index = new_index + 1; new_index = 0; int count = new_size - old_index; int leave = group->leave_queue.number; for (i=0;i<leave;i++) { if (old_index >= new_size) { count = 0; break; } uint32_t handle = group->leave_queue.data[i]; struct pair * p = &group->data[old_index]; if (handle == p->handle) { --count; ++old_index; if (p->ctx) { skynet_context_release(p->ctx); } } else if ( handle > p->handle) { group->data[new_index] = group->data[old_index]; ++new_index; ++old_index; --i; } else { skynet_error(from, "Try to remove a none exist handle : %x", handle); } } while (new_index < count) { group->data[new_index] = group->data[old_index]; ++new_index; ++old_index; } group->leave_queue.number = 0; group->number = new_index; }