improve action thread

This commit is contained in:
xianjimli 2020-02-13 10:19:58 +08:00
parent 729c5249b7
commit fb95d6757f
16 changed files with 1104 additions and 198 deletions

View File

@ -240,12 +240,14 @@ static inline void widget_image_color2data(unsigned char* d, bitmap_format_t for
}
}
static inline void widget_draw_antialiasing_for_point(frr_image_info_t* image_info, canvas_t* canvas, int px, int py,
float_t e, rgba_t n_color, rgba_t o_color) {
static inline void widget_draw_antialiasing_for_point(frr_image_info_t* image_info,
canvas_t* canvas, int px, int py, float_t e,
rgba_t n_color, rgba_t o_color) {
int32_t p = 0;
unsigned char a = (unsigned char)(e * n_color.a);
if (canvas->clip_left <= px && px <= canvas->clip_right && canvas->clip_top <= py && py <= canvas->clip_bottom) {
if (canvas->clip_left <= px && px <= canvas->clip_right && canvas->clip_top <= py &&
py <= canvas->clip_bottom) {
IMAGE_COLOR2COLOR_BLEND(n_color, o_color, a);
p = (int32_t)GET_IMAGE_POINT(image_info->bpp, image_info->stride, image_info->w, image_info->h,
px, py);

View File

@ -22,45 +22,6 @@
#include "tkc/mem.h"
#include "tkc/action_queue.h"
qaction_t* qaction_init(qaction_t* action, qaction_exec_t exec, void* args, uint32_t args_size) {
return_value_if_fail(action != NULL & exec != NULL, NULL);
return_value_if_fail(args_size <= sizeof(action->args), NULL);
memset(action, 0x00, sizeof(qaction_t));
action->exec = exec;
if (args != NULL) {
memcpy(action->args, args, args_size);
}
return action;
}
ret_t qaction_set_on_event(qaction_t* action, qaction_on_event_t on_event) {
return_value_if_fail(action != NULL, RET_BAD_PARAMS);
action->on_event = on_event;
return RET_OK;
}
ret_t qaction_notify(qaction_t* action, event_t* event) {
return_value_if_fail(action != NULL && event != NULL, RET_BAD_PARAMS);
if (action->on_event != NULL) {
action->on_event(action, event);
}
return RET_OK;
}
ret_t qaction_exec(qaction_t* action) {
return_value_if_fail(action != NULL && action->exec != NULL, RET_BAD_PARAMS);
return action->exec(action);
}
action_queue_t* action_queue_create(uint16_t capacity) {
uint16_t size = 0;
action_queue_t* q = NULL;
@ -76,10 +37,11 @@ action_queue_t* action_queue_create(uint16_t capacity) {
return q;
}
ret_t action_queue_recv(action_queue_t* q, qaction_t* action) {
ret_t action_queue_recv(action_queue_t* q, qaction_t** action) {
return_value_if_fail(q != NULL && action != NULL, RET_BAD_PARAMS);
if (q->r != q->w || q->full) {
memcpy(action, q->actions + q->r, sizeof(*action));
*action = q->actions[q->r];
q->actions[q->r] = NULL;
if ((q->r + 1) < q->capacity) {
q->r++;
} else {
@ -93,10 +55,11 @@ ret_t action_queue_recv(action_queue_t* q, qaction_t* action) {
return RET_FAIL;
}
ret_t action_queue_send(action_queue_t* q, const qaction_t* action) {
ret_t action_queue_send(action_queue_t* q, qaction_t* action) {
return_value_if_fail(q != NULL && action != NULL, RET_BAD_PARAMS);
if (q->r != q->w || !q->full) {
memcpy(q->actions + q->w, action, sizeof(*action));
q->actions[q->w] = action;
if ((q->w + 1) < q->capacity) {
q->w++;
} else {
@ -113,7 +76,13 @@ ret_t action_queue_send(action_queue_t* q, const qaction_t* action) {
}
ret_t action_queue_destroy(action_queue_t* q) {
uint32_t i = 0;
return_value_if_fail(q != NULL, RET_BAD_PARAMS);
for (i = 0; i < q->capacity; i++) {
if (q->actions[i] != NULL) {
qaction_destroy(q->actions[i]);
}
}
TKMEM_FREE(q);
return RET_OK;

View File

@ -22,94 +22,16 @@
#ifndef TK_ACTION_QUEUE_H
#define TK_ACTION_QUEUE_H
#include "tkc/event.h"
#include "tkc/qaction.h"
BEGIN_C_DECLS
struct _qaction_t;
typedef struct _qaction_t qaction_t;
typedef ret_t (*qaction_exec_t)(qaction_t* action);
typedef ret_t (*qaction_on_event_t)(qaction_t* action, event_t* event);
/**
* @class qaction_t
* actionaction_queue中
*/
struct _qaction_t {
/**
* @property {qaction_on_event_t} on_event
* @annotation ["readable"]
*
*/
qaction_on_event_t on_event;
/**
* @property {qaction_exec_t} exec
* @annotation ["readable"]
*
*/
qaction_exec_t exec;
/**
* @property {uint32_t*} args
* @annotation ["readable"]
* exec的参数(action而不同)
*/
uint32_t args[8];
};
/**
* @method qaction_init
*
*
* @param {qaction_t*} action action对象
* @param {qaction_exec_t} exec
* @param {void*} args
* @param {uint32_t} args_size (sizeof(action->args))
*
* @return {qaction_t*} action对象
*/
qaction_t* qaction_init(qaction_t* action, qaction_exec_t exec, void* args, uint32_t args_size);
/**
* @method qaction_set_on_event
* (线)
*
* @param {qaction_t*} action action对象
* @param {qaction_on_event_t} on_event
*
* @return {ret_t} RET_OK表示成功
*/
ret_t qaction_set_on_event(qaction_t* action, qaction_on_event_t on_event);
/**
* @method qaction_notify
*
*
* @param {qaction_t*} action action对象
* @param {event_t**} event event对象
*
* @return {ret_t} RET_OK表示成功
*/
ret_t qaction_notify(qaction_t* action, event_t* event);
/**
* @method qaction_exec
*
*
* @param {qaction_t*} action action对象
*
* @return {ret_t} RET_OK表示成功
*/
ret_t qaction_exec(qaction_t* action);
typedef struct _action_queue_t {
uint16_t r;
uint16_t w;
uint16_t full;
uint16_t capacity;
qaction_t actions[1];
qaction_t* actions[1];
} action_queue_t;
/**
@ -128,22 +50,22 @@ action_queue_t* action_queue_create(uint16_t capacity);
*
*
* @param {action_queue_t*} q action_queue对象
* @param {qaction_t*} action action对象
* @param {qaction_t**} action action对象
*
* @return {ret_t} RET_OK表示成功
*/
ret_t action_queue_recv(action_queue_t* q, qaction_t* action);
ret_t action_queue_recv(action_queue_t* q, qaction_t** action);
/**
* @method action_queue_send
*
*
* @param {action_queue_t*} q action_queue对象
* @param {const qaction_t*} action action对象
* @param {qaction_t*} action action对象
*
* @return {ret_t} RET_OK表示成功
*/
ret_t action_queue_send(action_queue_t* q, const qaction_t* action);
ret_t action_queue_send(action_queue_t* q, qaction_t* action);
/**
* @method action_queue_destroy

View File

@ -25,24 +25,25 @@
#include "tkc/waitable_action_queue.h"
static void* action_thread_entry(void* args) {
qaction_t action;
done_event_t done;
action_thread_t* thread = (action_thread_t*)args;
memset(&action, 0x00, sizeof(action));
thread->quit = FALSE;
thread->quited = FALSE;
log_debug("action thread start\n");
while (!(thread->quit)) {
memset(&action, 0x00, sizeof(action));
qaction_t* action = NULL;
while (waitable_action_queue_recv(thread->queue, &action, 1000) == RET_OK) {
ret_t ret = qaction_exec(&action);
ret_t ret = qaction_exec(action);
if (ret == RET_QUIT) {
thread->quit = TRUE;
}
qaction_notify(&action, done_event_init(&done, ret));
if (qaction_notify(action, done_event_init(&done, ret)) == RET_NOT_IMPL) {
qaction_destroy(action);
}
thread->executed_actions_nr++;
}
@ -126,8 +127,7 @@ static ret_t qaction_quit_exec(qaction_t* action) {
}
static ret_t action_thread_quit(action_thread_t* thread) {
qaction_t action;
qaction_t* a = qaction_init(&action, qaction_quit_exec, NULL, 0);
qaction_t* a = qaction_create(qaction_quit_exec, NULL, 0);
return_value_if_fail(thread != NULL, RET_BAD_PARAMS);
if (thread->quited || !thread->queue) {

View File

@ -89,9 +89,10 @@ action_thread_t* action_thread_create(void);
/**
* @method action_thread_create_with_queue
* @annotation ["constructor"]
* @param {waitable_action_queue_t*} queue queue对象
* action_thread对象
*
* @param {waitable_action_queue_t*} queue queue对象
*
* @return {action_thread_t*} action_thread对象
*/
action_thread_t* action_thread_create_with_queue(waitable_action_queue_t* queue);

View File

@ -28,7 +28,7 @@ BEGIN_C_DECLS
/**
* @class action_thread_pool_t
* 线
* action线程
*/
typedef struct _action_thread_pool_t {
/**

73
src/tkc/qaction.c Normal file
View File

@ -0,0 +1,73 @@
/**
* File: qaction.c
* Author: AWTK Develop Team
* Brief: qaction
*
* Copyright (c) 2020 - 2020 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2020-02-06 Li XianJing <xianjimli@hotmail.com> created
*
*/
#include "tkc/mem.h"
#include "tkc/qaction.h"
qaction_t* qaction_create(qaction_exec_t exec, void* args, uint32_t args_size) {
qaction_t* action = NULL;
uint32_t size = sizeof(qaction_t) + args_size;
return_value_if_fail(exec != NULL, NULL);
action = TKMEM_ALLOC(size);
return_value_if_fail(action != NULL, NULL);
memset(action, 0x00, size);
action->exec = exec;
if (args != NULL) {
memcpy(action->args, args, args_size);
}
return action;
}
ret_t qaction_set_on_event(qaction_t* action, qaction_on_event_t on_event) {
return_value_if_fail(action != NULL, RET_BAD_PARAMS);
action->on_event = on_event;
return RET_OK;
}
ret_t qaction_notify(qaction_t* action, event_t* event) {
return_value_if_fail(action != NULL && event != NULL, RET_BAD_PARAMS);
if (action->on_event != NULL) {
return action->on_event(action, event);
}
return RET_NOT_IMPL;
}
ret_t qaction_exec(qaction_t* action) {
return_value_if_fail(action != NULL && action->exec != NULL, RET_BAD_PARAMS);
return action->exec(action);
}
ret_t qaction_destroy(qaction_t* q) {
return_value_if_fail(q != NULL, RET_BAD_PARAMS);
memset(q, 0x00, sizeof(qaction_t));
TKMEM_FREE(q);
return RET_OK;
}

120
src/tkc/qaction.h Normal file
View File

@ -0,0 +1,120 @@
/**
* File: qaction.h
* Author: AWTK Develop Team
* Brief: qaction
*
* Copyright (c) 2020 - 2020 Guangzhou ZHIYUAN Electronics Co.,Ltd.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* License file for more details.
*
*/
/**
* History:
* ================================================================
* 2020-02-06 Li XianJing <xianjimli@hotmail.com> created
*
*/
#ifndef TK_QACTION_H
#define TK_QACTION_H
#include "tkc/event.h"
BEGIN_C_DECLS
struct _qaction_t;
typedef struct _qaction_t qaction_t;
typedef ret_t (*qaction_exec_t)(qaction_t* action);
typedef ret_t (*qaction_on_event_t)(qaction_t* action, event_t* event);
/**
* @class qaction_t
* actionaction queue中
*/
struct _qaction_t {
/**
* @property {qaction_exec_t} exec
* @annotation ["readable"]
*
*/
qaction_exec_t exec;
/**
* @property {qaction_on_event_t} on_event
* @annotation ["readable"]
*
*/
qaction_on_event_t on_event;
/**
* @property {uint32_t*} args
* @annotation ["readable"]
* exec的参数(action而不同)
*/
uint32_t args[1];
};
/**
* @method qaction_create
* action对象
*
* @param {qaction_exec_t} exec
* @param {void*} args
* @param {uint32_t} args_size
*
* @return {qaction_t*} action对象
*/
qaction_t* qaction_create(qaction_exec_t exec, void* args, uint32_t args_size);
/**
* @method qaction_set_on_event
* (线)
*
*> exec执行完成后EVT\_DONE事件EVT\_DONE事件中调用qaction\_destroy函数销毁action
*
* @param {qaction_t*} action action对象
* @param {qaction_on_event_t} on_event
*
* @return {ret_t} RET_OK表示成功
*/
ret_t qaction_set_on_event(qaction_t* action, qaction_on_event_t on_event);
/**
* @method qaction_exec
*
*
* @param {qaction_t*} action action对象
*
* @return {ret_t} RET_OK表示成功
*/
ret_t qaction_exec(qaction_t* action);
/**
* @method qaction_notify
*
*
* @param {qaction_t*} action action对象
* @param {event_t**} event event对象
*
* @return {ret_t} RET_OK表示成功
*/
ret_t qaction_notify(qaction_t* action, event_t* event);
/**
* @method qaction_destroy
*
*
* @param {qaction_t*} q qaction对象
*
* @return {ret_t} RET_OK表示成功
*/
ret_t qaction_destroy(qaction_t* q);
END_C_DECLS
#endif /*TK_QACTION_H*/

View File

@ -62,7 +62,7 @@ error:
return NULL;
}
ret_t waitable_action_queue_recv(waitable_action_queue_t* q, qaction_t* action,
ret_t waitable_action_queue_recv(waitable_action_queue_t* q, qaction_t** action,
uint32_t timeout_ms) {
ret_t ret = RET_FAIL;
return_value_if_fail(q != NULL && action != NULL, RET_BAD_PARAMS);
@ -80,7 +80,7 @@ ret_t waitable_action_queue_recv(waitable_action_queue_t* q, qaction_t* action,
return ret;
}
ret_t waitable_action_queue_send(waitable_action_queue_t* q, const qaction_t* action,
ret_t waitable_action_queue_send(waitable_action_queue_t* q, qaction_t* action,
uint32_t timeout_ms) {
ret_t ret = RET_FAIL;
return_value_if_fail(q != NULL && action != NULL, RET_BAD_PARAMS);

View File

@ -51,12 +51,12 @@ waitable_action_queue_t* waitable_action_queue_create(uint16_t capacity);
*
*
* @param {waitable_action_queue_t*} q waitable_action_queue对象
* @param {qaction_t*} action action对象
* @param {qaction_t**} action action对象
* @param {uint32_t} timeout_ms (ms)
*
* @return {ret_t} RET_OK表示成功
*/
ret_t waitable_action_queue_recv(waitable_action_queue_t* q, qaction_t* action,
ret_t waitable_action_queue_recv(waitable_action_queue_t* q, qaction_t** action,
uint32_t timeout_ms);
/**
@ -64,12 +64,12 @@ ret_t waitable_action_queue_recv(waitable_action_queue_t* q, qaction_t* action,
*
*
* @param {waitable_action_queue_t*} q waitable_action_queue对象
* @param {const qaction_t*} action action对象
* @param {qaction_t*} action action对象
* @param {uint32_t} timeout_ms (ms)
*
* @return {ret_t} RET_OK表示成功
*/
ret_t waitable_action_queue_send(waitable_action_queue_t* q, const qaction_t* action,
ret_t waitable_action_queue_send(waitable_action_queue_t* q, qaction_t* action,
uint32_t timeout_ms);
/**

View File

@ -3,14 +3,14 @@
#define NR 10
TEST(ActionQueue, basic) {
uint16_t i = 0;
qaction_t r;
qaction_t w;
action_queue_t* q = action_queue_create(NR);
static ret_t qaction_dummy_exec(qaction_t* action) {
return RET_OK;
}
memset(&r, 0x00, sizeof(r));
memset(&w, 0x00, sizeof(w));
TEST(ActionQueue, basic) {
qaction_t* r = NULL;
action_queue_t* q = action_queue_create(NR);
qaction_t* w = qaction_create(qaction_dummy_exec, NULL, 0);
ASSERT_EQ(q != NULL, true);
ASSERT_EQ(q->r, 0);
@ -18,31 +18,39 @@ TEST(ActionQueue, basic) {
ASSERT_EQ(q->full, FALSE);
ASSERT_EQ(q->capacity, 10);
w.args[0] = 1234;
w->args[0] = 1234;
ASSERT_EQ(action_queue_recv(q, &r), RET_FAIL);
ASSERT_EQ(action_queue_send(q, &w), RET_OK);
ASSERT_EQ(action_queue_send(q, w), RET_OK);
ASSERT_EQ(action_queue_recv(q, &r), RET_OK);
ASSERT_EQ(memcmp(&r, &w, sizeof(r)), 0);
ASSERT_EQ(r, w);
ASSERT_EQ(action_queue_recv(q, &r), RET_FAIL);
for (i = 0; i < NR; i++) {
w.args[0] = i;
ASSERT_EQ(action_queue_send(q, &w), RET_OK);
qaction_destroy(w);
action_queue_destroy(q);
}
ASSERT_EQ(q->full, TRUE);
ASSERT_EQ(action_queue_send(q, &w), RET_FAIL);
TEST(ActionQueue, multi) {
uint32_t i = 0;
qaction_t* r = NULL;
action_queue_t* q = action_queue_create(NR);
for (i = 0; i < NR; i++) {
qaction_t* w = qaction_create(qaction_dummy_exec, NULL, 0);
w->args[0] = i;
ASSERT_EQ(action_queue_send(q, w), RET_OK);
}
for (i = 0; i < NR; i++) {
ASSERT_EQ(action_queue_recv(q, &r), RET_OK);
ASSERT_EQ(r.args[0], i);
ASSERT_EQ(r->args[0], i);
qaction_destroy(r);
}
ASSERT_EQ(action_queue_recv(q, &r), RET_FAIL);
ASSERT_EQ(q->full, FALSE);
ASSERT_EQ(action_queue_send(q, &w), RET_OK);
ASSERT_EQ(action_queue_send(q, &w), RET_OK);
ASSERT_EQ(action_queue_recv(q, &r), RET_OK);
for (i = 0; i < NR; i++) {
qaction_t* w = qaction_create(qaction_dummy_exec, NULL, 0);
w->args[0] = i;
ASSERT_EQ(action_queue_send(q, w), RET_OK);
}
action_queue_destroy(q);
}

View File

@ -12,6 +12,7 @@ static std::atomic<int> exec_times;
static ret_t qaction_dummy_on_event(qaction_t* action, event_t* e) {
if (e->type == EVT_DONE) {
log_debug("done\n");
qaction_destroy(action);
}
return RET_OK;
@ -25,15 +26,11 @@ static ret_t qaction_dummy_exec(qaction_t* action) {
void test() {
uint32_t i = 0;
qaction_t action;
action_thread_pool_t* pool = NULL;
qaction_t* a = qaction_init(&action, qaction_dummy_exec, NULL, 0);
qaction_set_on_event(a, qaction_dummy_on_event);
pool = action_thread_pool_create(10, 2);
action_thread_pool_t* pool = action_thread_pool_create(10, 2);
for (i = 0; i < NR; i++) {
qaction_t* a = qaction_create(qaction_dummy_exec, NULL, 0);
qaction_set_on_event(a, qaction_dummy_on_event);
action_thread_pool_exec(pool, a);
}

View File

@ -3,13 +3,14 @@
#include "tkc/platform.h"
#include "tkc/action_thread.h"
#define NR 10
#define NR 10000
static uint32_t exec_times = 0;
static ret_t qaction_dummy_on_event(qaction_t* action, event_t* e) {
if (e->type == EVT_DONE) {
log_debug("done\n");
qaction_destroy(action);
}
return RET_OK;
@ -35,19 +36,15 @@ static ret_t on_quit(void* ctx, action_thread_t* thread) {
void test() {
uint32_t i = 0;
qaction_t action;
action_thread_t* thread1 = NULL;
qaction_t* a = qaction_init(&action, qaction_dummy_exec, NULL, 0);
qaction_set_on_event(a, qaction_dummy_on_event);
thread1 = action_thread_create();
action_thread_t* thread1 = action_thread_create();
action_thread_set_on_idle(thread1, on_idle, NULL);
action_thread_set_on_quit(thread1, on_quit, NULL);
for (i = 0; i < NR; i++) {
qaction_t* a = qaction_create(qaction_dummy_exec, NULL, 0);
qaction_set_on_event(a, qaction_dummy_on_event);
action_thread_exec(thread1, a);
action_thread_exec(thread1, a);
action_thread_exec(thread1, a);
}
sleep_ms(2000);

View File

@ -5,7 +5,6 @@
#define NR 100000
static uint32_t exec_times = 0;
static uint32_t destroy_times = 0;
static waitable_action_queue_t* q;
static ret_t qaction_exec_dummy(qaction_t* req) {
@ -15,12 +14,13 @@ static ret_t qaction_exec_dummy(qaction_t* req) {
static void* consumer(void* args) {
uint32_t n = 0;
qaction_t action;
qaction_t* action = NULL;
log_debug("consumer start\n");
while (waitable_action_queue_recv(q, &action, 3000) == RET_OK) {
n++;
qaction_exec(&action);
qaction_exec(action);
qaction_destroy(action);
}
log_debug("consumer done\n");
@ -29,12 +29,10 @@ static void* consumer(void* args) {
static void* producer(void* args) {
uint32_t i = 0;
qaction_t action;
qaction_t* a = qaction_init(&action, qaction_exec_dummy, NULL, 0);
uint32_t id = tk_pointer_to_int(args);
log_debug("p=%u start\n", id);
for (i = 0; i < NR; i++) {
qaction_t* a = qaction_create(qaction_exec_dummy, NULL, 0);
if (waitable_action_queue_send(q, a, 3000) != RET_OK) {
log_debug("send timeout\n");
break;
@ -73,7 +71,7 @@ void test() {
tk_thread_destroy(p4);
waitable_action_queue_destroy(q);
log_debug("exec_times=%u destroy_times=%u\n", exec_times, destroy_times);
log_debug("exec_times=%u \n", exec_times);
}
#include "tkc/platform.h"

File diff suppressed because it is too large Load Diff

View File

@ -10,6 +10,7 @@
"license": "ISC",
"dependencies": {
"crawler": "^1.2.1",
"novel-segment": "^2.5.4",
"url": "^0.11.0"
}
}