/* Copyright (c) 2012-2016, The Linux Foundation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following
* disclaimer in the documentation and/or other materials provided
* with the distribution.
* * Neither the name of The Linux Foundation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
* BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
* BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
* OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN
* IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*/
// System dependencies
#include <string.h>
#include <utils/Errors.h>
// Camera dependencies
#include "QCameraQueue.h"
extern "C" {
#include "mm_camera_dbg.h"
}
namespace qcamera {
/*===========================================================================
* FUNCTION : QCameraQueue
*
* DESCRIPTION: default constructor of QCameraQueue
*
* PARAMETERS : None
*
* RETURN : None
*==========================================================================*/
QCameraQueue::QCameraQueue()
{
pthread_mutex_init(&m_lock, NULL);
cam_list_init(&m_head.list);
m_size = 0;
m_dataFn = NULL;
m_userData = NULL;
m_active = true;
}
/*===========================================================================
* FUNCTION : QCameraQueue
*
* DESCRIPTION: constructor of QCameraQueue
*
* PARAMETERS :
* @data_rel_fn : function ptr to release node data internal resource
* @user_data : user data ptr
*
* RETURN : None
*==========================================================================*/
QCameraQueue::QCameraQueue(release_data_fn data_rel_fn, void *user_data)
{
pthread_mutex_init(&m_lock, NULL);
cam_list_init(&m_head.list);
m_size = 0;
m_dataFn = data_rel_fn;
m_userData = user_data;
m_active = true;
}
/*===========================================================================
* FUNCTION : ~QCameraQueue
*
* DESCRIPTION: deconstructor of QCameraQueue
*
* PARAMETERS : None
*
* RETURN : None
*==========================================================================*/
QCameraQueue::~QCameraQueue()
{
flush();
pthread_mutex_destroy(&m_lock);
}
/*===========================================================================
* FUNCTION : init
*
* DESCRIPTION: Put the queue to active state (ready to enqueue and dequeue)
*
* PARAMETERS : None
*
* RETURN : None
*==========================================================================*/
void QCameraQueue::init()
{
pthread_mutex_lock(&m_lock);
m_active = true;
pthread_mutex_unlock(&m_lock);
}
/*===========================================================================
* FUNCTION : isEmpty
*
* DESCRIPTION: return if the queue is empty or not
*
* PARAMETERS : None
*
* RETURN : true -- queue is empty; false -- not empty
*==========================================================================*/
bool QCameraQueue::isEmpty()
{
bool flag = true;
pthread_mutex_lock(&m_lock);
if (m_size > 0) {
flag = false;
}
pthread_mutex_unlock(&m_lock);
return flag;
}
/*===========================================================================
* FUNCTION : enqueue
*
* DESCRIPTION: enqueue data into the queue
*
* PARAMETERS :
* @data : data to be enqueued
*
* RETURN : true -- success; false -- failed
*==========================================================================*/
bool QCameraQueue::enqueue(void *data)
{
bool rc;
camera_q_node *node =
(camera_q_node *)malloc(sizeof(camera_q_node));
if (NULL == node) {
LOGE("No memory for camera_q_node");
return false;
}
memset(node, 0, sizeof(camera_q_node));
node->data = data;
pthread_mutex_lock(&m_lock);
if (m_active) {
cam_list_add_tail_node(&node->list, &m_head.list);
m_size++;
rc = true;
} else {
free(node);
rc = false;
}
pthread_mutex_unlock(&m_lock);
return rc;
}
/*===========================================================================
* FUNCTION : enqueueWithPriority
*
* DESCRIPTION: enqueue data into queue with priority, will insert into the
* head of the queue
*
* PARAMETERS :
* @data : data to be enqueued
*
* RETURN : true -- success; false -- failed
*==========================================================================*/
bool QCameraQueue::enqueueWithPriority(void *data)
{
bool rc;
camera_q_node *node =
(camera_q_node *)malloc(sizeof(camera_q_node));
if (NULL == node) {
LOGE("No memory for camera_q_node");
return false;
}
memset(node, 0, sizeof(camera_q_node));
node->data = data;
pthread_mutex_lock(&m_lock);
if (m_active) {
struct cam_list *p_next = m_head.list.next;
m_head.list.next = &node->list;
p_next->prev = &node->list;
node->list.next = p_next;
node->list.prev = &m_head.list;
m_size++;
rc = true;
} else {
free(node);
rc = false;
}
pthread_mutex_unlock(&m_lock);
return rc;
}
/*===========================================================================
* FUNCTION : peek
*
* DESCRIPTION: return the head element without removing it
*
* PARAMETERS : None
*
* RETURN : data ptr. NULL if not any data in the queue.
*==========================================================================*/
void* QCameraQueue::peek()
{
camera_q_node* node = NULL;
void* data = NULL;
struct cam_list *head = NULL;
struct cam_list *pos = NULL;
pthread_mutex_lock(&m_lock);
if (m_active) {
head = &m_head.list;
pos = head->next;
if (pos != head) {
node = member_of(pos, camera_q_node, list);
}
}
pthread_mutex_unlock(&m_lock);
if (NULL != node) {
data = node->data;
}
return data;
}
/*===========================================================================
* FUNCTION : dequeue
*
* DESCRIPTION: dequeue data from the queue
*
* PARAMETERS :
* @bFromHead : if true, dequeue from the head
* if false, dequeue from the tail
*
* RETURN : data ptr. NULL if not any data in the queue.
*==========================================================================*/
void* QCameraQueue::dequeue(bool bFromHead)
{
camera_q_node* node = NULL;
void* data = NULL;
struct cam_list *head = NULL;
struct cam_list *pos = NULL;
pthread_mutex_lock(&m_lock);
if (m_active) {
head = &m_head.list;
if (bFromHead) {
pos = head->next;
} else {
pos = head->prev;
}
if (pos != head) {
node = member_of(pos, camera_q_node, list);
cam_list_del_node(&node->list);
m_size--;
}
}
pthread_mutex_unlock(&m_lock);
if (NULL != node) {
data = node->data;
free(node);
}
return data;
}
/*===========================================================================
* FUNCTION : dequeue
*
* DESCRIPTION: dequeue data from the queue
*
* PARAMETERS :
* @match : matching function callback
* @match_data : the actual data to be matched
*
* RETURN : data ptr. NULL if not any data in the queue.
*==========================================================================*/
void* QCameraQueue::dequeue(match_fn_data match, void *match_data){
camera_q_node* node = NULL;
struct cam_list *head = NULL;
struct cam_list *pos = NULL;
void* data = NULL;
if ( NULL == match || NULL == match_data ) {
return NULL;
}
pthread_mutex_lock(&m_lock);
if (m_active) {
head = &m_head.list;
pos = head->next;
while(pos != head) {
node = member_of(pos, camera_q_node, list);
pos = pos->next;
if (NULL != node) {
if ( match(node->data, m_userData, match_data) ) {
cam_list_del_node(&node->list);
m_size--;
data = node->data;
free(node);
pthread_mutex_unlock(&m_lock);
return data;
}
}
}
}
pthread_mutex_unlock(&m_lock);
return NULL;
}
/*===========================================================================
* FUNCTION : flush
*
* DESCRIPTION: flush all nodes from the queue, queue will be empty after this
* operation.
*
* PARAMETERS : None
*
* RETURN : None
*==========================================================================*/
void QCameraQueue::flush(){
camera_q_node* node = NULL;
struct cam_list *head = NULL;
struct cam_list *pos = NULL;
pthread_mutex_lock(&m_lock);
if (m_active) {
head = &m_head.list;
pos = head->next;
while(pos != head) {
node = member_of(pos, camera_q_node, list);
pos = pos->next;
cam_list_del_node(&node->list);
m_size--;
if (NULL != node->data) {
if (m_dataFn) {
m_dataFn(node->data, m_userData);
}
free(node->data);
}
free(node);
}
m_size = 0;
m_active = false;
}
pthread_mutex_unlock(&m_lock);
}
/*===========================================================================
* FUNCTION : flushNodes
*
* DESCRIPTION: flush only specific nodes, depending on
* the given matching function.
*
* PARAMETERS :
* @match : matching function
*
* RETURN : None
*==========================================================================*/
void QCameraQueue::flushNodes(match_fn match){
camera_q_node* node = NULL;
struct cam_list *head = NULL;
struct cam_list *pos = NULL;
if ( NULL == match ) {
return;
}
pthread_mutex_lock(&m_lock);
if (m_active) {
head = &m_head.list;
pos = head->next;
while(pos != head) {
node = member_of(pos, camera_q_node, list);
pos = pos->next;
if ( match(node->data, m_userData) ) {
cam_list_del_node(&node->list);
m_size--;
if (NULL != node->data) {
if (m_dataFn) {
m_dataFn(node->data, m_userData);
}
free(node->data);
}
free(node);
}
}
}
pthread_mutex_unlock(&m_lock);
}
/*===========================================================================
* FUNCTION : flushNodes
*
* DESCRIPTION: flush only specific nodes, depending on
* the given matching function.
*
* PARAMETERS :
* @match : matching function
*
* RETURN : None
*==========================================================================*/
void QCameraQueue::flushNodes(match_fn_data match, void *match_data){
camera_q_node* node = NULL;
struct cam_list *head = NULL;
struct cam_list *pos = NULL;
if ( NULL == match ) {
return;
}
pthread_mutex_lock(&m_lock);
if (m_active) {
head = &m_head.list;
pos = head->next;
while(pos != head) {
node = member_of(pos, camera_q_node, list);
pos = pos->next;
if ( match(node->data, m_userData, match_data) ) {
cam_list_del_node(&node->list);
m_size--;
if (NULL != node->data) {
if (m_dataFn) {
m_dataFn(node->data, m_userData);
}
free(node->data);
}
free(node);
}
}
}
pthread_mutex_unlock(&m_lock);
}
}; // namespace qcamera