/* * Copyright (C) 2016 The Android Open Source Project * Copyright (C) 2016 Mopria Alliance, Inc. * Copyright (C) 2013 Hewlett-Packard Development Company, L.P. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef _GNU_SOURCE #define _GNU_SOURCE #endif #include <stdio.h> #include <stdlib.h> #include <pthread.h> #include <semaphore.h> #include "wprint_msgq.h" #include "wprint_debug.h" #define TAG "wprint_msgq" #define _SEM_NAME_LENGTH 16 typedef struct { msg_q_id msgq_id; char name[_SEM_NAME_LENGTH]; int max_msgs; int max_msg_length; int num_msgs; sem_t sem_count; sem_t *sem_ptr; pthread_mutex_t mutex; pthread_mutexattr_t mutexattr; unsigned long read_offset; unsigned long write_offset; } _msgq_hdr_t; msg_q_id msgQCreate(int max_msgs, int max_msg_length) { _msgq_hdr_t *msgq; int msgq_size; msgq_size = sizeof(_msgq_hdr_t) + max_msgs * max_msg_length; msgq = (_msgq_hdr_t *) malloc((size_t)msgq_size); if (msgq) { memset((char *) msgq, 0, (size_t)msgq_size); msgq->msgq_id = (msg_q_id) msgq; msgq->max_msgs = max_msgs; msgq->max_msg_length = max_msg_length; msgq->num_msgs = 0; // create a mutex to protect access to this structure pthread_mutexattr_init(&(msgq->mutexattr)); pthread_mutexattr_settype(&(msgq->mutexattr), PTHREAD_MUTEX_RECURSIVE_NP); pthread_mutex_init(&msgq->mutex, &msgq->mutexattr); // create a counting semaphore msgq->sem_ptr = &msgq->sem_count; sem_init(msgq->sem_ptr, 0, 0); // PRIVATE, EMPTY msgq->read_offset = 0; msgq->write_offset = 0; } return ((msg_q_id) msgq); } status_t msgQDelete(msg_q_id msgQ) { _msgq_hdr_t *msgq = (msg_q_id) msgQ; if (msgq) { pthread_mutex_lock(&(msgq->mutex)); if (msgq->num_msgs) { LOGE("Warning msgQDelete() called on queue with %d messages", msgq->num_msgs); } sem_destroy(&(msgq->sem_count)); pthread_mutex_unlock(&(msgq->mutex)); pthread_mutex_destroy(&(msgq->mutex)); free((void *) msgq); } return (msgq ? OK : ERROR); } status_t msgQSend(msg_q_id msgQ, const char *buffer, unsigned long nbytes, int timeout, int priority) { _msgq_hdr_t *msgq = (msg_q_id) msgQ; char *msg_loc; status_t result = ERROR; // validate function arguments if (msgq && (timeout == NO_WAIT) && (priority == MSG_Q_FIFO)) { pthread_mutex_lock(&(msgq->mutex)); // ensure the message conforms to size limits and there is room in the msgQ if ((nbytes <= msgq->max_msg_length) && (msgq->num_msgs < msgq->max_msgs)) { msg_loc = (char *) msgq + sizeof(_msgq_hdr_t) + (msgq->write_offset * msgq->max_msg_length); memcpy(msg_loc, buffer, nbytes); msgq->write_offset = (msgq->write_offset + 1) % msgq->max_msgs; msgq->num_msgs++; sem_post(msgq->sem_ptr); result = OK; } pthread_mutex_unlock(&(msgq->mutex)); } return result; } status_t msgQReceive(msg_q_id msgQ, char *buffer, unsigned long max_nbytes, int timeout) { _msgq_hdr_t *msgq = (msg_q_id) msgQ; char *msg_loc; status_t result = ERROR; if (msgq && buffer && ((timeout == WAIT_FOREVER) || (timeout == NO_WAIT))) { if (timeout == WAIT_FOREVER) { result = (status_t) sem_wait(msgq->sem_ptr); } else { /* timeout is NO_WAIT */ result = (status_t) sem_trywait(msgq->sem_ptr); } if (result == 0) { pthread_mutex_lock(&(msgq->mutex)); msg_loc = (char *) msgq + sizeof(_msgq_hdr_t) + (msgq->read_offset * msgq->max_msg_length); memcpy(buffer, msg_loc, max_nbytes); msgq->read_offset = (msgq->read_offset + 1) % msgq->max_msgs; msgq->num_msgs--; pthread_mutex_unlock(&(msgq->mutex)); } } return result; } int msgQNumMsgs(msg_q_id msgQ) { _msgq_hdr_t *msgq = (msg_q_id) msgQ; int num_msgs = -1; if (msgq) { pthread_mutex_lock(&(msgq->mutex)); num_msgs = msgq->num_msgs; pthread_mutex_unlock(&(msgq->mutex)); } return num_msgs; }