mm_camera_cmd_thread
需求:一个新的线程,监听和分发处理一些命令。
在实际的应用中,这种使用场景是非常多见的。
typedef void (*mm_camera_cmd_cb_t)(mm_camera_cmdcb_t * cmd_cb, void* user_data);
typedef struct { uint8_t is_active; /*indicates whether thread is active or not */ cam_queue_t cmd_queue; /* cmd queue (queuing dataCB, asyncCB, or exitCMD) */ pthread_t cmd_pid; /* cmd thread ID */ cam_semaphore_t cmd_sem; /* semaphore for cmd thread */ cam_semaphore_t sync_sem; /* semaphore for synchronization with cmd thread */ mm_camera_cmd_cb_t cb; /* cb for cmd */ /* Command处理的Callback函数,由用户注册 */ void* user_data; /* user_data for cb */ char threadName[THREAD_NAME_SIZE]; } mm_camera_cmd_thread_t;
1. 新建线程
int32_t mm_camera_cmd_thread_launch(mm_camera_cmd_thread_t * cmd_thread, mm_camera_cmd_cb_t cb, void* user_data) { int32_t rc = 0; cam_sem_init(&cmd_thread->cmd_sem, 0); cam_sem_init(&cmd_thread->sync_sem, 0); cam_queue_init(&cmd_thread->cmd_queue); cmd_thread->cb = cb; cmd_thread->user_data = user_data; cmd_thread->is_active = TRUE; /* launch the thread */ pthread_create(&cmd_thread->cmd_pid, NULL, mm_camera_cmd_thread, (void *)cmd_thread); return rc; }
太简单了,无话可说。
2. 线程的其他控制函数
int32_t mm_camera_cmd_thread_name(const char* name) // 设置线程名字 { int32_t rc = 0; /* name the thread */ if (name && strlen(name)) prctl(PR_SET_NAME, (unsigned long)name, 0, 0, 0); return rc; } int32_t mm_camera_cmd_thread_stop(mm_camera_cmd_thread_t * cmd_thread) // 停止线程 { int32_t rc = 0; mm_camera_cmdcb_t* node = (mm_camera_cmdcb_t *)malloc(sizeof(mm_camera_cmdcb_t)); if (NULL == node) { CDBG_ERROR("%s: No memory for mm_camera_cmdcb_t", __func__); return -1; } memset(node, 0, sizeof(mm_camera_cmdcb_t)); node->cmd_type = MM_CAMERA_CMD_TYPE_EXIT; cam_queue_enq(&cmd_thread->cmd_queue, node); cam_sem_post(&cmd_thread->cmd_sem); /* wait until cmd thread exits */ if (pthread_join(cmd_thread->cmd_pid, NULL) != 0) { // 这里很重要,说明调用该函数是会给工作线程收尸 CDBG("%s: pthread dead already\n", __func__); } return rc; } int32_t mm_camera_cmd_thread_destroy(mm_camera_cmd_thread_t * cmd_thread) { int32_t rc = 0; cam_queue_deinit(&cmd_thread->cmd_queue); cam_sem_destroy(&cmd_thread->cmd_sem); cam_sem_destroy(&cmd_thread->sync_sem); memset(cmd_thread, 0, sizeof(mm_camera_cmd_thread_t)); return rc; } int32_t mm_camera_cmd_thread_release(mm_camera_cmd_thread_t * cmd_thread) { int32_t rc = 0; rc = mm_camera_cmd_thread_stop(cmd_thread); if (0 == rc) { rc = mm_camera_cmd_thread_destroy(cmd_thread); } return rc; }
3. 线程主体
static void *mm_camera_cmd_thread(void *data) { int running = 1; int ret; mm_camera_cmd_thread_t *cmd_thread = (mm_camera_cmd_thread_t *)data; mm_camera_cmdcb_t* node = NULL; mm_camera_cmd_thread_name(cmd_thread->threadName); do { do { ret = cam_sem_wait(&cmd_thread->cmd_sem); if (ret != 0 && errno != EINVAL) { CDBG_ERROR("%s: cam_sem_wait error (%s)", __func__, strerror(errno)); return NULL; } } while (ret != 0); /* we got notified about new cmd avail in cmd queue */ node = (mm_camera_cmdcb_t*)cam_queue_deq(&cmd_thread->cmd_queue); while (node != NULL) { // 处理这些命令 switch (node->cmd_type) { case MM_CAMERA_CMD_TYPE_EVT_CB: case MM_CAMERA_CMD_TYPE_DATA_CB: case MM_CAMERA_CMD_TYPE_REQ_DATA_CB: case MM_CAMERA_CMD_TYPE_SUPER_BUF_DATA_CB: case MM_CAMERA_CMD_TYPE_CONFIG_NOTIFY: case MM_CAMERA_CMD_TYPE_START_ZSL: case MM_CAMERA_CMD_TYPE_STOP_ZSL: case MM_CAMERA_CMD_TYPE_GENERAL: case MM_CAMERA_CMD_TYPE_FLUSH_QUEUE: if (NULL != cmd_thread->cb) { // 这些用户定义的命令的处理使用用户指定的 Callback 函数 cmd_thread->cb(node, cmd_thread->user_data); } break; case MM_CAMERA_CMD_TYPE_EXIT: default: running = 0; break; } free(node); node = (mm_camera_cmdcb_t*)cam_queue_deq(&cmd_thread->cmd_queue); } /* (node != NULL) */ } while (running); return NULL; }
typedef enum { MM_CAMERA_CMD_TYPE_DATA_CB, /* dataB CMD */ MM_CAMERA_CMD_TYPE_EVT_CB, /* evtCB CMD */ MM_CAMERA_CMD_TYPE_EXIT, /* EXIT */ MM_CAMERA_CMD_TYPE_REQ_DATA_CB,/* request data */ MM_CAMERA_CMD_TYPE_SUPER_BUF_DATA_CB, /* superbuf dataB CMD */ MM_CAMERA_CMD_TYPE_CONFIG_NOTIFY, /* configure notify mode */ MM_CAMERA_CMD_TYPE_START_ZSL, /* start zsl snapshot for channel */ MM_CAMERA_CMD_TYPE_STOP_ZSL, /* stop zsl snapshot for channel */ MM_CAMERA_CMD_TYPE_FLUSH_QUEUE, /* flush queue */ MM_CAMERA_CMD_TYPE_GENERAL, /* general cmd */ MM_CAMERA_CMD_TYPE_MAX } mm_camera_cmdcb_type_t; typedef struct { uint32_t stream_id; uint32_t frame_idx; uint32_t flags; mm_camera_buf_def_t *buf; /* ref to buf */ } mm_camera_buf_info_t; typedef enum { MM_CAMERA_GENERIC_CMD_TYPE_AE_BRACKETING, MM_CAMERA_GENERIC_CMD_TYPE_AF_BRACKETING, MM_CAMERA_GENERIC_CMD_TYPE_FLASH_BRACKETING, MM_CAMERA_GENERIC_CMD_TYPE_ZOOM_1X, MM_CAMERA_GENERIC_CMD_TYPE_CAPTURE_SETTING, } mm_camera_generic_cmd_type_t; typedef struct { mm_camera_generic_cmd_type_t type; uint32_t payload[32]; union { cam_capture_frame_config_t frame_config; }; } mm_camera_generic_cmd_t; typedef struct { uint32_t frame_idx; cam_stream_type_t stream_type; } mm_camera_flush_cmd_t; typedef struct { mm_camera_cmdcb_type_t cmd_type; union { mm_camera_buf_info_t buf; /* frame buf if dataCB */ mm_camera_event_t evt; /* evt if evtCB */ mm_camera_super_buf_t superbuf; /* superbuf if superbuf dataCB*/ mm_camera_req_buf_t req_buf; /* num of buf requested */ mm_camera_flush_cmd_t flush_cmd; /* frame idx boundary for flush superbuf queue*/ mm_camera_super_buf_notify_mode_t notify_mode; /* notification mode */ mm_camera_generic_cmd_t gen_cmd; } u; } mm_camera_cmdcb_t;
4. 线程目的
该线程的主要目的是为了 监听 Kernel或者 Demon 中的事件。
static void mm_camera_event_notify(void* user_data) // 回调。Kernel事件监听线程的回调。会有一个线程不断地 poll Kernel 的事件。具体实现,后期文章再细讲 { struct v4l2_event ev; struct msm_v4l2_event_data *msm_evt = NULL; int rc; mm_camera_event_t evt; memset(&evt, 0, sizeof(mm_camera_event_t)); mm_camera_obj_t *my_obj = (mm_camera_obj_t*)user_data; if (NULL != my_obj) { /* read evt */ memset(&ev, 0, sizeof(ev)); rc = ioctl(my_obj->ctrl_fd, VIDIOC_DQEVENT, &ev); if (rc >= 0 && ev.id == MSM_CAMERA_MSM_NOTIFY) { msm_evt = (struct msm_v4l2_event_data *)ev.u.data; switch (msm_evt->command) { case CAM_EVENT_TYPE_DAEMON_PULL_REQ: evt.server_event_type = CAM_EVENT_TYPE_DAEMON_PULL_REQ; mm_camera_enqueue_evt(my_obj, &evt); break; case CAM_EVENT_TYPE_MAP_UNMAP_DONE: // 该事件是用来表示 发 Demon 消息时的返回结果 pthread_mutex_lock(&my_obj->evt_lock); my_obj->evt_rcvd.server_event_type = msm_evt->command; my_obj->evt_rcvd.status = msm_evt->status; pthread_cond_signal(&my_obj->evt_cond); pthread_mutex_unlock(&my_obj->evt_lock); break; case CAM_EVENT_TYPE_INT_TAKE_JPEG: case CAM_EVENT_TYPE_INT_TAKE_RAW: { evt.server_event_type = msm_evt->command; mm_camera_enqueue_evt(my_obj, &evt); } break; case MSM_CAMERA_PRIV_SHUTDOWN: { CDBG_ERROR("%s: Camera Event DAEMON DIED received", __func__); evt.server_event_type = CAM_EVENT_TYPE_DAEMON_DIED; mm_camera_enqueue_evt(my_obj, &evt); } break; case CAM_EVENT_TYPE_CAC_DONE: { evt.server_event_type = CAM_EVENT_TYPE_CAC_DONE; mm_camera_enqueue_evt(my_obj, &evt); } break; default: break; } } } } int32_t mm_camera_enqueue_evt(mm_camera_obj_t *my_obj, mm_camera_event_t *event) { int32_t rc = 0; mm_camera_cmdcb_t *node = NULL; node = (mm_camera_cmdcb_t *)malloc(sizeof(mm_camera_cmdcb_t)); if (NULL != node) { memset(node, 0, sizeof(mm_camera_cmdcb_t)); node->cmd_type = MM_CAMERA_CMD_TYPE_EVT_CB; // MM_CAMERA_CMD_TYPE_EVT_CB node->u.evt = *event; /* enqueue to evt cmd thread */ cam_queue_enq(&(my_obj->evt_thread.cmd_queue), node); // evt_thread 的事件的唯一入口 /* wake up evt cmd thread */ cam_sem_post(&(my_obj->evt_thread.cmd_sem)); } else { CDBG_ERROR("%s: No memory for mm_camera_node_t", __func__); rc = -1; } return rc; }