doubao_chat/lib/net/libduer-device/platform/source-linux/lightduer_events.c

250 lines
7.3 KiB
C

/**
* Copyright (2017) Baidu Inc. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
//
// File: lightduer_events.c
// Auth: Zhang Leliang (zhangleliang@baidu.com)
// Desc: Light duer events looper.
#include "lightduer_events.h"
#include <pthread.h>
#include <stdbool.h>
#include <sys/time.h>
#include <unistd.h>
#include "lightduer_connagent.h"
#include "lightduer_lib.h"
#include "lightduer_log.h"
#include "lightduer_memory.h"
#include "lightduer_priority_conf.h"
typedef struct _duer_queue_message_s {
duer_events_func _callback;
int _what;
void *_data;
struct _duer_queue_message_s *_pre;
struct _duer_queue_message_s *_next;
} duer_eq_message;
typedef struct _duer_events_struct {
pthread_t _task;
pthread_mutex_t _mutex;
pthread_cond_t _cond;
duer_eq_message *_head;
duer_eq_message *_tail;
char *_name;
bool _shutdown;
} duer_events_t;
static unsigned long long duer_events_timestamp()
{
struct timeval tv;
int ret = gettimeofday(&tv, NULL);
if (ret) {
DUER_LOGE("gettimeofday error");
return 0;
}
unsigned long long time_in_microseconds = tv.tv_sec * 1000 + tv.tv_usec / 1000;
return time_in_microseconds;
}
static void *duer_events_task(void *context)
{
duer_events_t *events = (duer_events_t *)(context);
unsigned long long runtime = 0;
duer_eq_message *message;
char *name = NULL;
const int NAME_LEN = 16;
DUER_LOGD("duer_events_task");
if (events == NULL) {
DUER_LOGE("duer_events_task events is NULL");
return NULL;
}
name = (char *)DUER_MALLOC(NAME_LEN);
if (name) {
snprintf(name, NAME_LEN, "%s", events->_name);
pthread_setname_np(events->_task, name);
DUER_FREE(name);
name = NULL;
}
do {
pthread_mutex_lock(&events->_mutex);
while (events->_tail == NULL && !events->_shutdown) {
pthread_cond_wait(&events->_cond, &events->_mutex);
}
if (events->_shutdown) {
pthread_mutex_unlock(&events->_mutex);
pthread_exit(0);
}
message = events->_tail;
events->_tail = events->_tail->_pre;
if (events->_tail == NULL) {
events->_head = NULL;
}
pthread_mutex_unlock(&events->_mutex);
if (message->_callback) {
runtime = duer_events_timestamp();
DUER_LOGD("[%s] <== event begin = %p", events->_name, message->_callback);
message->_callback(message->_what, message->_data);
runtime = duer_events_timestamp() - runtime;
if (runtime > 50) {
DUER_LOGW("[%s] <== event end = %p, timespent = %ld, message:%p", events->_name, message->_callback, runtime, message);
}
}
DUER_FREE(message);
message = NULL;
} while (1);
return NULL;
}
duer_events_handler duer_events_create(const char *name, size_t stack_size, size_t queue_length)
{
duer_events_t *events = NULL;
int rs = DUER_ERR_FAILED;
DUER_LOGD("duer_events_create: %s", name);
do {
if (name == NULL) {
name = "default";
}
events = (duer_events_t *)DUER_MALLOC(sizeof(duer_events_t));
if (!events) {
DUER_LOGE("[%s] Alloc the events resource failed!", name);
break;
}
DUER_MEMSET(events, 0, sizeof(duer_events_t));
events->_name = (char *)DUER_MALLOC(DUER_STRLEN(name) + 1);
if (events->_name) {
DUER_MEMCPY(events->_name, name, DUER_STRLEN(name) + 1);
}
pthread_mutex_init(&events->_mutex, NULL);
pthread_cond_init(&events->_cond, NULL);
events->_head = NULL;
events->_tail = NULL;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_DETACHED);
if (stack_size > 0) {
pthread_attr_setstacksize(&attr, stack_size);
}
// struct sched_param pri_param;
// pri_param.sched_priority = duer_priority_get(duer_priority_get_task_id(name));
// pthread_attr_setschedparam(&attr, &pri_param);
DUER_LOGD("duer_events_create: %s", name);
int status = pthread_create(&events->_task, &attr, duer_events_task, (void *)events);
pthread_attr_destroy(&attr);
if (status) {
DUER_LOGE("pthread_create failed! status:%d", status);
break;
}
rs = DUER_OK;
} while (0);
if (rs != DUER_OK) {
duer_events_destroy(events);
events = NULL;
}
return events;
}
int duer_events_call(duer_events_handler handler, duer_events_func func, int what, void *object)
{
int rs = DUER_ERR_FAILED;
duer_events_t *events = (duer_events_t *)handler;
do {
if (events == NULL) {
break;
}
DUER_LOGD("duer_events_call, name:%s, what:%d, obj:%p", events->_name, what, object);
duer_eq_message *message = DUER_MALLOC(sizeof(duer_eq_message));
if (message == NULL) {
DUER_LOGE("malloc duer_eq_message fail!!");
break;
}
message->_callback = func;
message->_what = what;
message->_data = object;
message->_pre = NULL;
pthread_mutex_lock(&events->_mutex);
if (events->_head) {
events->_head->_pre = message;
}
message->_next = events->_head;
events->_head = message;
if (events->_tail == NULL) {
events->_tail = message;
}
pthread_mutex_unlock(&events->_mutex);
if (events->_tail == message) {
pthread_cond_signal(&events->_cond);
}
rs = DUER_OK;
} while (0);
if (rs < 0 && events != NULL && events->_name != NULL) {
DUER_LOGE("[%s] Queue send failed!", events->_name);
}
return rs;
}
void duer_events_destroy(duer_events_handler handler)
{
duer_events_t *events = (duer_events_t *)handler;
if (events) {
if (!events->_shutdown) {
events->_shutdown = true;
} else {
DUER_LOGI("already destroy!");
return;
}
pthread_cond_broadcast(&events->_cond);
sleep(1);// wait for the thread exit
pthread_mutex_lock(&events->_mutex);
while (events->_head) {
duer_eq_message *message = events->_head;
events->_head = events->_head->_next;
DUER_FREE(message);
}
pthread_mutex_unlock(&events->_mutex);
pthread_mutex_destroy(&events->_mutex);
pthread_cond_destroy(&events->_cond);
if (events->_name) {
DUER_FREE(events->_name);
events->_name = NULL;
}
DUER_FREE(events);
}
}