mm_camera_poll_thread
mm_camera_poll_thread
先看下提供的外部接口:
/* mm_camera_poll_thread_commit_updates 功能:同步之前挂起的所有异步事件 mm_camera_poll_thread_add_poll_fd 功能:添加一个新的文件句柄到 polling thread,polling thread 负责监听该文件句柄的IO事件 mm_camera_poll_thread_del_poll_fd 功能:将指定文件句柄从 polling thread 中删除,polling thread 不在负责监听该文件句柄的IO事件 mm_camera_poll_thread_launch 功能:初始化并启动 polling thread mm_camera_poll_thread_release 功能:释放 polling thread */
从上述API中,大体可以猜测出,polling thread 的核心功能:新建一个线程,负责 polling 用户指定的 文件句柄。
那么下面看看具体实现:
/* mm_camera.h */ typedef struct { mm_camera_poll_thread_type_t poll_type; /* array to store poll fd and cb info * for MM_CAMERA_POLL_TYPE_EVT, only index 0 is valid; * for MM_CAMERA_POLL_TYPE_DATA, depends on valid stream fd */ mm_camera_poll_entry_t poll_entries[MAX_STREAM_NUM_IN_BUNDLE]; int32_t pfds[2]; pthread_t pid; int32_t state; int timeoutms; uint32_t cmd; struct pollfd poll_fds[MAX_STREAM_NUM_IN_BUNDLE + 1]; uint8_t num_fds; pthread_mutex_t mutex; pthread_cond_t cond_v; int32_t status; char threadName[THREAD_NAME_SIZE]; //void *my_obj; } mm_camera_poll_thread_t; typedef enum { MM_CAMERA_POLL_TYPE_EVT, MM_CAMERA_POLL_TYPE_DATA, MM_CAMERA_POLL_TYPE_MAX } mm_camera_poll_thread_type_t; /* function ptr defined for poll notify CB, * registered at poll thread with poll fd */ typedef void (*mm_camera_poll_notify_t)(void *user_data); typedef struct { int32_t fd; mm_camera_poll_notify_t notify_cb; uint32_t handler; void* user_data; } mm_camera_poll_entry_t;
int32_t mm_camera_poll_thread_launch(mm_camera_poll_thread_t * poll_cb, mm_camera_poll_thread_type_t poll_type) // poll_type 指定 polling thread 监听的事件类型,是普通事件或者是数据事件 { int32_t rc = 0; size_t i = 0, cnt = 0; poll_cb->poll_type = poll_type; //Initialize poll_fds cnt = sizeof(poll_cb->poll_fds) / sizeof(poll_cb->poll_fds[0]); for (i = 0; i < cnt; i++) { poll_cb->poll_fds[i].fd = -1; } //Initialize poll_entries cnt = sizeof(poll_cb->poll_entries) / sizeof(poll_cb->poll_entries[0]); for (i = 0; i < cnt; i++) { poll_cb->poll_entries[i].fd = -1; } //Initialize pipe fds poll_cb->pfds[0] = -1; poll_cb->pfds[1] = -1; rc = pipe(poll_cb->pfds); // 这里很关键,这里创建了一个管道,这个管道负责什么事情呢? if(rc < 0) { CDBG_ERROR("%s: pipe open rc=%d\n", __func__, rc); return -1; } poll_cb->timeoutms = -1; /* Infinite seconds */ CDBG("%s: poll_type = %d, read fd = %d, write fd = %d timeout = %d", __func__, poll_cb->poll_type, poll_cb->pfds[0], poll_cb->pfds[1],poll_cb->timeoutms); pthread_mutex_init(&poll_cb->mutex, NULL); pthread_cond_init(&poll_cb->cond_v, NULL); /* launch the thread */ pthread_mutex_lock(&poll_cb->mutex); poll_cb->status = 0; pthread_create(&poll_cb->pid, NULL, mm_camera_poll_thread, (void *)poll_cb); // 新建线程,负责 polling ,线程主体是: mm_camera_poll_thread if(!poll_cb->status) { pthread_cond_wait(&poll_cb->cond_v, &poll_cb->mutex); // 创建线程的方式以阻塞方式,这里通过检测 poll_cb_status 来确保线程创建成功并以成功调度 } pthread_mutex_unlock(&poll_cb->mutex); CDBG("%s: End",__func__); return rc; }
int32_t mm_camera_poll_thread_release(mm_camera_poll_thread_t *poll_cb) { int32_t rc = 0; if(MM_CAMERA_POLL_TASK_STATE_STOPPED == poll_cb->state) { CDBG_ERROR("%s: err, poll thread is not running.\n", __func__); return rc; } /* send exit signal to poll thread */ mm_camera_poll_sig(poll_cb, MM_CAMERA_PIPE_CMD_EXIT); // 发送 退出 命令到 polling thread,具体实现下文分析 /* wait until poll thread exits */ if (pthread_join(poll_cb->pid, NULL) != 0) { // 等待 polling thread 成功退出 CDBG_ERROR("%s: pthread dead already\n", __func__); } /* close pipe */ if(poll_cb->pfds[0] >= 0) { // 关闭管道的读写端 close(poll_cb->pfds[0]); } if(poll_cb->pfds[1] >= 0) { close(poll_cb->pfds[1]); } pthread_mutex_destroy(&poll_cb->mutex); pthread_cond_destroy(&poll_cb->cond_v); memset(poll_cb, 0, sizeof(mm_camera_poll_thread_t)); poll_cb->pfds[0] = -1; poll_cb->pfds[1] = -1; return rc; }
接下来,来看最重要的 polling thread 的线程主体:
static void *mm_camera_poll_thread(void *data) { mm_camera_poll_thread_t *poll_cb = (mm_camera_poll_thread_t *)data; mm_camera_cmd_thread_name(poll_cb->threadName); // 设置线程的名字,当然,这个名字是由用户决定的 /* add pipe read fd into poll first */ poll_cb->poll_fds[poll_cb->num_fds++].fd = poll_cb->pfds[0]; // poll_cb->pfds 是管道的读写端的的文件句柄,而 poll_cb->pfds[0] 是管道读端文件句柄。 mm_camera_poll_sig_done(poll_cb); // 设置 poll_cb->status 为 TRUE mm_camera_poll_set_state(poll_cb, MM_CAMERA_POLL_TASK_STATE_POLL); // 将 poll_cb->state 设置为 MM_CAMERA_POLL_TASK_STATE_POLL. return mm_camera_poll_fn(poll_cb); // 核心逻辑 }
static void mm_camera_poll_sig_done(mm_camera_poll_thread_t *poll_cb) { pthread_mutex_lock(&poll_cb->mutex); poll_cb->status = TRUE; // 设置 poll_cb->status 为 TRUE。在创建 polling thread 的父线程中,会检测该状态,故需要 加锁。 pthread_cond_signal(&poll_cb->cond_v); CDBG("%s: done, in mutex", __func__); pthread_mutex_unlock(&poll_cb->mutex); }
static void *mm_camera_poll_fn(mm_camera_poll_thread_t *poll_cb) { int rc = 0, i; if (NULL == poll_cb) { CDBG_ERROR("%s: poll_cb is NULL!\n", __func__); return NULL; } CDBG("%s: poll type = %d, num_fd = %d poll_cb = %p\n", __func__, poll_cb->poll_type, poll_cb->num_fds,poll_cb); do { for(i = 0; i < poll_cb->num_fds; i++) { poll_cb->poll_fds[i].events = POLLIN|POLLRDNORM|POLLPRI; // 将所有的 pollfd 要监听的事件设置为: POLLIN|POLLRDNORM|POLLPRI , POLLIN: 有数据可读; POLLRDNORM:普通数据可读; POLLPRI:紧迫数据可读 } rc = poll(poll_cb->poll_fds, poll_cb->num_fds, poll_cb->timeoutms); if(rc > 0) { // 存在就绪的 fd ,rc为就绪的 fd 的个数 if ((poll_cb->poll_fds[0].revents & POLLIN) && (poll_cb->poll_fds[0].revents & POLLRDNORM)) { // poll_cb->poll_fds[0]为读就绪状态。poll_fds[0] 始终是 pipe ,即在 launch 中创建的 pipe,该 pipe 用来接收用户命令。 /* if we have data on pipe, we only process pipe in this iteration */ CDBG("%s: cmd received on pipe\n", __func__); mm_camera_poll_proc_pipe(poll_cb); // 处理该事件 } else { // 否则,就是监听的用户文件句柄为读就绪状态 for(i=1; i<poll_cb->num_fds; i++) { // poll_fds[1] 开始就是用户文件句柄 /* Checking for ctrl events */ if ((poll_cb->poll_type == MM_CAMERA_POLL_TYPE_EVT) && (poll_cb->poll_fds[i].revents & POLLPRI)) { // 如果 polling thread type 为 MM_CAMERA_POLL_TYPE_EVT,并且实际检测到的时间类型为 POLLPRI CDBG("%s: mm_camera_evt_notify\n", __func__); if (NULL != poll_cb->poll_entries[i-1].notify_cb) { poll_cb->poll_entries[i-1].notify_cb(poll_cb->poll_entries[i-1].user_data); // 回调用户注册的 回调函数 } } if ((MM_CAMERA_POLL_TYPE_DATA == poll_cb->poll_type) && (poll_cb->poll_fds[i].revents & POLLIN) && (poll_cb->poll_fds[i].revents & POLLRDNORM)) { // polling thread type 为MM_CAMERA_POLL_TYPE_DATA CDBG("%s: mm_stream_data_notify\n", __func__); if (NULL != poll_cb->poll_entries[i-1].notify_cb) { poll_cb->poll_entries[i-1].notify_cb(poll_cb->poll_entries[i-1].user_data); } } } } } else { /* in error case sleep 10 us and then continue. hard coded here */ usleep(10); continue; } } while ((poll_cb != NULL) && (poll_cb->state == MM_CAMERA_POLL_TASK_STATE_POLL)); return NULL; }
mm_camera_poll_proc_pipe 是处理管道发送的命令,那么一定是不断的读管道,然后进行处理。在分析此函数之前,我们先分析写管道。
int32_t mm_camera_poll_thread_add_poll_fd(mm_camera_poll_thread_t * poll_cb, uint32_t handler, int32_t fd, mm_camera_poll_notify_t notify_cb, void* userdata, mm_camera_call_type_t call_type) { int32_t rc = -1; uint8_t idx = 0; if (MM_CAMERA_POLL_TYPE_DATA == poll_cb->poll_type) { // 如果是 监听数据,首先获取 stream index.所以可以猜测,每个 stream 都会通过 poll 监听 /* get stream idx from handler if CH type */ idx = mm_camera_util_get_index_by_handler(handler); } else { /* for EVT type, only idx=0 is valid */ idx = 0; } if (MAX_STREAM_NUM_IN_BUNDLE > idx) { // poll_cb->poll_entries 存放用户注册的信息 poll_cb->poll_entries[idx].fd = fd; poll_cb->poll_entries[idx].handler = handler; poll_cb->poll_entries[idx].notify_cb = notify_cb; poll_cb->poll_entries[idx].user_data = userdata; /* send poll entries updated signal to poll thread */ if (call_type == mm_camera_sync_call ) { // 同步调用 rc = mm_camera_poll_sig(poll_cb, MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED); } else { // 异步调用 rc = mm_camera_poll_sig_async(poll_cb, MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED_ASYNC ); } } else { CDBG_ERROR("%s: invalid handler %d (%d)", __func__, handler, idx); } return rc; }
static int32_t mm_camera_poll_sig(mm_camera_poll_thread_t *poll_cb, uint32_t cmd) { /* send through pipe */ /* get the mutex */ mm_camera_sig_evt_t cmd_evt; CDBG("%s: E cmd = %d", __func__,cmd); memset(&cmd_evt, 0, sizeof(cmd_evt)); cmd_evt.cmd = cmd; pthread_mutex_lock(&poll_cb->mutex); /* reset the statue to false */ poll_cb->status = FALSE; /* send cmd to worker */ ssize_t len = write(poll_cb->pfds[1], &cmd_evt, sizeof(cmd_evt)); if(len < 1) { CDBG_ERROR("%s: len = %lld, errno = %d", __func__, (long long int)len, errno); /* Avoid waiting for the signal */ pthread_mutex_unlock(&poll_cb->mutex); return 0; } CDBG("%s: begin IN mutex write done, len = %lld", __func__, (long long int)len); /* wait till worker task gives positive signal */ if (FALSE == poll_cb->status) { // 同步调用,等待 polling thread 成功接收到该命令 CDBG("%s: wait", __func__); pthread_cond_wait(&poll_cb->cond_v, &poll_cb->mutex); } /* done */ pthread_mutex_unlock(&poll_cb->mutex); CDBG("%s: X", __func__); return 0; }
static int32_t mm_camera_poll_sig_async(mm_camera_poll_thread_t *poll_cb, uint32_t cmd) { /* send through pipe */ /* get the mutex */ mm_camera_sig_evt_t cmd_evt; CDBG("%s: E cmd = %d", __func__,cmd); memset(&cmd_evt, 0, sizeof(cmd_evt)); cmd_evt.cmd = cmd; pthread_mutex_lock(&poll_cb->mutex); /* reset the statue to false */ poll_cb->status = FALSE; /* send cmd to worker */ ssize_t len = write(poll_cb->pfds[1], &cmd_evt, sizeof(cmd_evt)); // 异步调用,只是写管道 if (len < 1) { CDBG_ERROR("%s: len = %lld, errno = %d", __func__, (long long int)len, errno); /* Avoid waiting for the signal */ pthread_mutex_unlock(&poll_cb->mutex); return 0; } CDBG("%s: begin IN mutex write done, len = %lld", __func__, (long long int)len); pthread_mutex_unlock(&poll_cb->mutex); CDBG("%s: X", __func__); return 0; }
看完如何通过管道发送命令,继续看 polling thread 如何处理管道命令?
static void mm_camera_poll_proc_pipe(mm_camera_poll_thread_t *poll_cb) { ssize_t read_len; int i; mm_camera_sig_evt_t cmd_evt; read_len = read(poll_cb->pfds[0], &cmd_evt, sizeof(cmd_evt)); // 首先读管道,即读取发送的命令 CDBG("%s: read_fd = %d, read_len = %d, expect_len = %d cmd = %d", __func__, poll_cb->pfds[0], (int)read_len, (int)sizeof(cmd_evt), cmd_evt.cmd); switch (cmd_evt.cmd) { case MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED: case MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED_ASYNC: /* we always have index 0 for pipe read */ /* 重要:总是将 poll_cb->poll_fds[0]作为管道读的文件句柄 */ poll_cb->num_fds = 0; poll_cb->poll_fds[poll_cb->num_fds].fd = poll_cb->pfds[0]; poll_cb->poll_fds[poll_cb->num_fds].events = POLLIN|POLLRDNORM|POLLPRI; poll_cb->num_fds++; if (MM_CAMERA_POLL_TYPE_EVT == poll_cb->poll_type && poll_cb->num_fds < MAX_STREAM_NUM_IN_BUNDLE) { if (poll_cb->poll_entries[0].fd >= 0) { /* fd is valid, we update poll_fds */ poll_cb->poll_fds[poll_cb->num_fds].fd = poll_cb->poll_entries[0].fd; poll_cb->poll_fds[poll_cb->num_fds].events = POLLIN|POLLRDNORM|POLLPRI; poll_cb->num_fds++; } } else if (MM_CAMERA_POLL_TYPE_DATA == poll_cb->poll_type && poll_cb->num_fds <= MAX_STREAM_NUM_IN_BUNDLE) { for(i = 0; i < MAX_STREAM_NUM_IN_BUNDLE; i++) { if(poll_cb->poll_entries[i].fd >= 0) { /* fd is valid, we update poll_fds to this fd */ poll_cb->poll_fds[poll_cb->num_fds].fd = poll_cb->poll_entries[i].fd; poll_cb->poll_fds[poll_cb->num_fds].events = POLLIN|POLLRDNORM|POLLPRI; poll_cb->num_fds++; } else { /* fd is invalid, we set the entry to -1 to prevent polling. * According to spec, polling will not poll on entry with fd=-1. * If this is not the case, we need to skip these invalid fds * when updating this array. * We still keep fd=-1 in this array because this makes easier to * map cb associated with this fd once incoming data avail by directly * using the index-1(0 is reserved for pipe read, so need to reduce index by 1) */ poll_cb->poll_fds[poll_cb->num_fds].fd = -1; poll_cb->poll_fds[poll_cb->num_fds].events = 0; poll_cb->num_fds++; } } } if (cmd_evt.cmd != MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED_ASYNC) // 如果不是异步调用,就需要将 poll_cb->status 设置为 TRUE,表示已经接收并处理过命令,通知父线程 mm_camera_poll_sig_done(poll_cb); break; case MM_CAMERA_PIPE_CMD_COMMIT: mm_camera_poll_sig_done(poll_cb); break; case MM_CAMERA_PIPE_CMD_EXIT: default: mm_camera_poll_set_state(poll_cb, MM_CAMERA_POLL_TASK_STATE_STOPPED); mm_camera_poll_sig_done(poll_cb); break; } }
对于异步调用,必须提供一个接口来确保 polling thread 来处理异步命令。
int32_t mm_camera_poll_thread_commit_updates(mm_camera_poll_thread_t * poll_cb) { return mm_camera_poll_sig(poll_cb, MM_CAMERA_PIPE_CMD_COMMIT); // 要想确保,还是得通过一个同步命令调用 }
最后,来看看 mm_camera_poll_thread_del_poll_fd、
int32_t mm_camera_poll_thread_del_poll_fd(mm_camera_poll_thread_t * poll_cb, uint32_t handler, mm_camera_call_type_t call_type) { int32_t rc = -1; uint8_t idx = 0; if (MM_CAMERA_POLL_TYPE_DATA == poll_cb->poll_type) { /* get stream idx from handler if CH type */ idx = mm_camera_util_get_index_by_handler(handler); } else { /* for EVT type, only idx=0 is valid */ idx = 0; } if ((MAX_STREAM_NUM_IN_BUNDLE > idx) && (handler == poll_cb->poll_entries[idx].handler)) { /* reset poll entry */ poll_cb->poll_entries[idx].fd = -1; /* set fd to invalid */ poll_cb->poll_entries[idx].handler = 0; poll_cb->poll_entries[idx].notify_cb = NULL; /* send poll entries updated signal to poll thread */ if (call_type == mm_camera_sync_call ) { rc = mm_camera_poll_sig(poll_cb, MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED); } else { rc = mm_camera_poll_sig_async(poll_cb, MM_CAMERA_PIPE_CMD_POLL_ENTRIES_UPDATED_ASYNC ); } } else { CDBG_ERROR("%s: invalid handler %d (%d)", __func__, handler, idx); return -1; } return rc; }
非常明确的 一个函数。

浙公网安备 33010602011771号