Files
BPI-CM9-Linux/aml-comp/vendor/amlogic/ccdatabase/server/dataserver_reader.c
T

293 lines
7.7 KiB
C
Raw Normal View History

2026-08-13 11:28:40 +08:00
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include <fcntl.h>
#include <pthread.h>
#include <sys/eventfd.h>
#include "dataserver_reader.h"
#include "dataserver_reader_inner.h"
#ifdef LOG_LOGCAT
#define LOG_TAG "ccdataserver"
#include <log/log.h>
#define ds_inf(_fmt_,...) ALOGI("%s:%d "_fmt_, __func__, __LINE__, ##__VA_ARGS__)
#define ds_err(_fmt_,...) ALOGE("%s:%d "_fmt_, __func__, __LINE__, ##__VA_ARGS__)
#else
#define ds_inf(_fmt_,...) printf("I %s:%d "_fmt_"\n", __func__, __LINE__, ##__VA_ARGS__)
#define ds_err(_fmt_,...) printf("E %s:%d "_fmt_"\n", __func__, __LINE__, ##__VA_ARGS__)
#endif
static struct list_head inst_list = LIST_HEAD_INIT(inst_list);
pthread_mutex_t inst_list_lock = PTHREAD_MUTEX_INITIALIZER;
static ds_reader_t* find_reader(const char *devname)
{
ds_reader_t *reader = NULL;
ds_reader_checker_t *checker;
for (checker = DS_READ_TASKS_CHECKER_START;
/*
* no "corrupt or misinterpret".
*/
/* coverity[ptr_arith] */
checker < DS_READ_TASKS_CHECKER_STOP; checker++) {
if ((reader = (*checker)(devname)))
break;
}
return reader;
}
/*
* return NULL if pushed successfully,
* return the callback if fail
*/
static ds_data_callback_t*
push_callback(reader_inst_t *inst, ds_data_callback_t *callback)
{
int callback_found = 0;
pthread_mutex_lock(&inst->callback_list_lock);
/*same (callback_fn + callback_priv) will be added only once*/
{
ds_data_callback_t *cb;
list_for_each_entry(cb, &inst->callback_list, head) {
if (cb->fn.data_cb == callback->fn.data_cb && cb->priv == callback->priv) {
callback_found = 1;
break;
}
}
if (!callback_found) {
list_for_each_entry(cb, &inst->callback_wait_list, head) {
if (cb->fn.data_cb == callback->fn.data_cb && cb->priv == callback->priv) {
callback_found = 1;
break;
}
}
}
}
if (!callback_found)
list_add_tail(&callback->head, &inst->callback_wait_list);
pthread_mutex_unlock(&inst->callback_list_lock);
return callback_found? callback : NULL;
}
int ds_reader_start(const char *devname, const char *settings,
ds_data_callback_fn_t *data_callback, void *callback_priv)
{
reader_inst_t *inst = NULL;
int inst_new = 1;
int inst_ready = 0;
ds_inf("dev[%s], cb[%p:%p]", devname? devname:"null", data_callback, callback_priv);
if (!devname || !data_callback || !data_callback->data_cb) {
ds_err("incorrect parameter");
return -1;
}
/*create the callback node*/
ds_data_callback_t *callback =
(ds_data_callback_t *)calloc(1, sizeof(ds_data_callback_t));
if (callback) {
callback->fn = *data_callback;
callback->priv = callback_priv;
} else {
ds_err("no memory");
return -1;
}
/*make the callback running*/
pthread_mutex_lock(&inst_list_lock);
/*look for the inst(devname)*/
list_for_each_entry(inst, &inst_list, head) {
if (strcmp(inst->devname, devname) == 0) {
inst_new = 0;
break;
}
}
if (inst_new) {
/*inst(devname) not exists, start new*/
inst = (reader_inst_t *)calloc(1, sizeof(reader_inst_t));
if (inst) {
inst->fd = open(devname, O_RDWR);
if (inst->fd >= 0) {
ds_reader_t *reader = find_reader(devname);
if (reader) {
if (reader->set)
reader->set(inst, settings);
inst->read_task = reader->task;
strncpy(inst->devname, devname, MAX_SIZE_DEVNAME);
inst->devname[MAX_SIZE_DEVNAME - 1] = '\0';
INIT_LIST_HEAD(&inst->callback_list);
INIT_LIST_HEAD(&inst->callback_wait_list);
pthread_mutex_init(&inst->callback_list_lock, NULL);
push_callback(inst, callback);
inst->running = 1;
inst->evtfd = eventfd(0, 0);
pthread_create(&inst->thread, NULL, inst->read_task, inst);
/*link the new inst*/
list_add_tail(&inst->head, &inst_list);
inst_ready = 1;
ds_inf("reader[%s] not found, new started", devname);
} else {
close(inst->fd);
free(inst);
ds_err("device[%s] is not supported yet", devname);
}
} else {
free(inst);
ds_err("can not open device[%s], err(%d:%s)",
devname, errno, strerror(errno));
}
} else {
ds_err("no memory");
}
} else {
int callback_found = 0;
/*inst(devname) exists, just add callback to the inst*/
ds_data_callback_t *cb = push_callback(inst, callback);
callback_found = cb? 1 : 0;
if (callback_found)
free(callback);
inst_ready = 1;
ds_inf("reader[%s] found, data callback (%s)",
devname, callback_found? "found" : "added");
}
pthread_mutex_unlock(&inst_list_lock);
if (!inst_ready)
free(callback);
return inst_ready? 0 : -1;
}
int ds_reader_stop(char *devname,
ds_data_callback_fn_t *data_callback, void *callback_priv)
{
reader_inst_t *inst = NULL;
int inst_found = 0;
pthread_mutex_lock(&inst_list_lock);
ds_inf("dev[%s], cb[%p:%p]", devname, data_callback, callback_priv);
/*look for the inst(devname)*/
list_for_each_entry(inst, &inst_list, head) {
if (strcmp(inst->devname, devname) == 0) {
inst_found = 1;
break;
}
}
if (inst_found) {
int callback_lists_all_empty = 0;
pthread_mutex_lock(&inst->callback_list_lock);
/*remove the callbacks from the inst*/
ds_data_callback_t *cb, *cb_tmp;
list_for_each_entry_safe(cb, cb_tmp, &inst->callback_list, head) {
if (cb->fn.data_cb == data_callback->data_cb && cb->priv == callback_priv) {
list_del(&cb->head);
free(cb);
ds_inf("reader[%s] found, data callback removed", devname);
break;
}
}
list_for_each_entry_safe(cb, cb_tmp, &inst->callback_wait_list, head) {
if (cb->fn.data_cb == data_callback->data_cb && cb->priv == callback_priv) {
list_del(&cb->head);
free(cb);
ds_inf("reader[%s] found, data callback(waiting) removed", devname);
break;
}
}
if (list_empty(&inst->callback_list) && list_empty(&inst->callback_wait_list))
callback_lists_all_empty = 1;
pthread_mutex_unlock(&inst->callback_list_lock);
/*if no callback in the inst, stop the inst*/
if (callback_lists_all_empty) {
list_del(&inst->head);
inst->running = 0;
{
int64_t pad = 1;
write(inst->evtfd, &pad, sizeof(pad));
}
pthread_join(inst->thread, NULL);
ds_reader_t *reader = find_reader(inst->devname);
if (reader && reader->close)
reader->close(inst);
close(inst->fd);
close(inst->evtfd);
free(inst);
ds_inf("reader[%s] stopped, due to no callback", devname);
}
}
pthread_mutex_unlock(&inst_list_lock);
return 0;
}