#include #include #include #include #include #include #include #include #include "dataserver_reader.h" #include "dataserver_reader_inner.h" #ifdef LOG_LOGCAT #define LOG_TAG "ccdataserver" #include #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; }