mirror of
https://github.com/cloudwu/skynet.git
synced 2026-07-24 20:23:06 +00:00
使用spinlock,避免cas不能充分调度testdeadloop这样的用例
This commit is contained in:
@@ -32,12 +32,9 @@ struct message_queue {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct global_queue {
|
struct global_queue {
|
||||||
uint32_t head;
|
struct message_queue *head;
|
||||||
uint32_t tail;
|
struct message_queue *tail;
|
||||||
struct message_queue ** queue;
|
int lock;
|
||||||
// We use a separated flag array to ensure the mq is pushed.
|
|
||||||
// See the comments below.
|
|
||||||
struct message_queue *list;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct global_queue *Q = NULL;
|
static struct global_queue *Q = NULL;
|
||||||
@@ -51,57 +48,33 @@ void
|
|||||||
skynet_globalmq_push(struct message_queue * queue) {
|
skynet_globalmq_push(struct message_queue * queue) {
|
||||||
struct global_queue *q= Q;
|
struct global_queue *q= Q;
|
||||||
|
|
||||||
uint32_t tail = GP(__sync_fetch_and_add(&q->tail,1));
|
|
||||||
|
|
||||||
// only one thread can set the slot (change q->queue[tail] from NULL to queue)
|
// only one thread can set the slot (change q->queue[tail] from NULL to queue)
|
||||||
if (!__sync_bool_compare_and_swap(&q->queue[tail], NULL, queue)) {
|
LOCK(q)
|
||||||
// The queue may full seldom, save queue in list
|
assert(queue->next == NULL);
|
||||||
assert(queue->next == NULL);
|
if(q->tail) {
|
||||||
struct message_queue * last;
|
q->tail->next = queue;
|
||||||
do {
|
q->tail = queue;
|
||||||
last = q->list;
|
} else {
|
||||||
queue->next = last;
|
q->head = q->tail = queue;
|
||||||
} while(!__sync_bool_compare_and_swap(&q->list, last, queue));
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
UNLOCK(q)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct message_queue *
|
struct message_queue *
|
||||||
skynet_globalmq_pop() {
|
skynet_globalmq_pop() {
|
||||||
struct global_queue *q = Q;
|
struct global_queue *q = Q;
|
||||||
uint32_t head = q->head;
|
|
||||||
|
|
||||||
if (head == q->tail) {
|
LOCK(q)
|
||||||
// The queue is empty.
|
struct message_queue *mq = q->head;
|
||||||
return NULL;
|
if(mq) {
|
||||||
}
|
q->head = mq->next;
|
||||||
|
if(q->head == NULL) {
|
||||||
uint32_t head_ptr = GP(head);
|
assert(mq == q->tail);
|
||||||
|
q->tail = NULL;
|
||||||
struct message_queue * list = q->list;
|
|
||||||
if (list) {
|
|
||||||
// If q->list is not empty, try to load it back to the queue
|
|
||||||
struct message_queue *newhead = list->next;
|
|
||||||
if (__sync_bool_compare_and_swap(&q->list, list, newhead)) {
|
|
||||||
// try load list only once, if success , push it back to the queue.
|
|
||||||
list->next = NULL;
|
|
||||||
skynet_globalmq_push(list);
|
|
||||||
}
|
}
|
||||||
|
mq->next = NULL;
|
||||||
}
|
}
|
||||||
|
UNLOCK(q)
|
||||||
struct message_queue * mq = q->queue[head_ptr];
|
|
||||||
if (mq == NULL) {
|
|
||||||
// globalmq push not complete
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
if (!__sync_bool_compare_and_swap(&q->head, head, head+1)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
// only one thread can get the slot (change q->queue[head_ptr] to NULL)
|
|
||||||
if (!__sync_bool_compare_and_swap(&q->queue[head_ptr], mq, NULL)) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
return mq;
|
return mq;
|
||||||
}
|
}
|
||||||
@@ -243,8 +216,6 @@ void
|
|||||||
skynet_mq_init() {
|
skynet_mq_init() {
|
||||||
struct global_queue *q = skynet_malloc(sizeof(*q));
|
struct global_queue *q = skynet_malloc(sizeof(*q));
|
||||||
memset(q,0,sizeof(*q));
|
memset(q,0,sizeof(*q));
|
||||||
q->queue = skynet_malloc(MAX_GLOBAL_MQ * sizeof(struct message_queue *));
|
|
||||||
memset(q->queue, 0, sizeof(struct message_queue *) * MAX_GLOBAL_MQ);
|
|
||||||
Q=q;
|
Q=q;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
10
test/testdeadloop.lua
Normal file
10
test/testdeadloop.lua
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
local skynet = require "skynet"
|
||||||
|
local function dead_loop()
|
||||||
|
while true do
|
||||||
|
skynet.sleep(0)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
skynet.start(function()
|
||||||
|
skynet.fork(dead_loop)
|
||||||
|
end)
|
||||||
Reference in New Issue
Block a user