Home | History | Annotate | Download | only in lib
      1 /*
      2  * Copyright (C) 2016 The Android Open Source Project
      3  * Copyright (C) 2016 Mopria Alliance, Inc.
      4  * Copyright (C) 2013 Hewlett-Packard Development Company, L.P.
      5  *
      6  * Licensed under the Apache License, Version 2.0 (the "License");
      7  * you may not use this file except in compliance with the License.
      8  * You may obtain a copy of the License at
      9  *
     10  *      http://www.apache.org/licenses/LICENSE-2.0
     11  *
     12  * Unless required by applicable law or agreed to in writing, software
     13  * distributed under the License is distributed on an "AS IS" BASIS,
     14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     15  * See the License for the specific language governing permissions and
     16  * limitations under the License.
     17  */
     18 
     19 #ifndef _GNU_SOURCE
     20 #define _GNU_SOURCE
     21 #endif
     22 
     23 #include <stdio.h>
     24 #include <stdlib.h>
     25 #include <pthread.h>
     26 #include <semaphore.h>
     27 
     28 #include "wprint_msgq.h"
     29 #include "wprint_debug.h"
     30 
     31 #define TAG "wprint_msgq"
     32 
     33 #define _SEM_NAME_LENGTH    16
     34 
     35 typedef struct {
     36     msg_q_id msgq_id;
     37     char name[_SEM_NAME_LENGTH];
     38     int max_msgs;
     39     int max_msg_length;
     40     int num_msgs;
     41     sem_t sem_count;
     42     sem_t *sem_ptr;
     43     pthread_mutex_t mutex;
     44     pthread_mutexattr_t mutexattr;
     45     unsigned long read_offset;
     46     unsigned long write_offset;
     47 } _msgq_hdr_t;
     48 
     49 msg_q_id msgQCreate(int max_msgs, int max_msg_length) {
     50     _msgq_hdr_t *msgq;
     51     int msgq_size;
     52 
     53     msgq_size = sizeof(_msgq_hdr_t) + max_msgs * max_msg_length;
     54     msgq = (_msgq_hdr_t *) malloc((size_t)msgq_size);
     55 
     56     if (msgq) {
     57         memset((char *) msgq, 0, (size_t)msgq_size);
     58         msgq->msgq_id = (msg_q_id) msgq;
     59         msgq->max_msgs = max_msgs;
     60         msgq->max_msg_length = max_msg_length;
     61         msgq->num_msgs = 0;
     62 
     63         // create a mutex to protect access to this structure
     64         pthread_mutexattr_init(&(msgq->mutexattr));
     65         pthread_mutexattr_settype(&(msgq->mutexattr), PTHREAD_MUTEX_RECURSIVE_NP);
     66         pthread_mutex_init(&msgq->mutex, &msgq->mutexattr);
     67 
     68         // create a counting semaphore
     69         msgq->sem_ptr = &msgq->sem_count;
     70         sem_init(msgq->sem_ptr, 0, 0); // PRIVATE, EMPTY
     71 
     72         msgq->read_offset = 0;
     73         msgq->write_offset = 0;
     74     }
     75     return ((msg_q_id) msgq);
     76 }
     77 
     78 status_t msgQDelete(msg_q_id msgQ) {
     79     _msgq_hdr_t *msgq = (msg_q_id) msgQ;
     80 
     81     if (msgq) {
     82         pthread_mutex_lock(&(msgq->mutex));
     83         if (msgq->num_msgs) {
     84             LOGE("Warning msgQDelete() called on queue with %d messages", msgq->num_msgs);
     85         }
     86 
     87         sem_destroy(&(msgq->sem_count));
     88         pthread_mutex_unlock(&(msgq->mutex));
     89         pthread_mutex_destroy(&(msgq->mutex));
     90         free((void *) msgq);
     91     }
     92     return (msgq ? OK : ERROR);
     93 }
     94 
     95 status_t msgQSend(msg_q_id msgQ, const char *buffer, unsigned long nbytes, int timeout,
     96         int priority) {
     97     _msgq_hdr_t *msgq = (msg_q_id) msgQ;
     98     char *msg_loc;
     99     status_t result = ERROR;
    100 
    101     // validate function arguments
    102     if (msgq && (timeout == NO_WAIT) && (priority == MSG_Q_FIFO)) {
    103         pthread_mutex_lock(&(msgq->mutex));
    104 
    105         // ensure the message conforms to size limits and there is room in the msgQ
    106         if ((nbytes <= msgq->max_msg_length) && (msgq->num_msgs < msgq->max_msgs)) {
    107             msg_loc = (char *) msgq + sizeof(_msgq_hdr_t) +
    108                     (msgq->write_offset * msgq->max_msg_length);
    109             memcpy(msg_loc, buffer, nbytes);
    110             msgq->write_offset = (msgq->write_offset + 1) % msgq->max_msgs;
    111             msgq->num_msgs++;
    112             sem_post(msgq->sem_ptr);
    113             result = OK;
    114         }
    115 
    116         pthread_mutex_unlock(&(msgq->mutex));
    117     }
    118     return result;
    119 }
    120 
    121 status_t msgQReceive(msg_q_id msgQ, char *buffer, unsigned long max_nbytes, int timeout) {
    122     _msgq_hdr_t *msgq = (msg_q_id) msgQ;
    123     char *msg_loc;
    124     status_t result = ERROR;
    125 
    126     if (msgq && buffer && ((timeout == WAIT_FOREVER) || (timeout == NO_WAIT))) {
    127         if (timeout == WAIT_FOREVER) {
    128             result = (status_t) sem_wait(msgq->sem_ptr);
    129         } else {
    130             /* timeout is NO_WAIT */
    131             result = (status_t) sem_trywait(msgq->sem_ptr);
    132         }
    133 
    134         if (result == 0) {
    135             pthread_mutex_lock(&(msgq->mutex));
    136 
    137             msg_loc = (char *) msgq + sizeof(_msgq_hdr_t) +
    138                     (msgq->read_offset * msgq->max_msg_length);
    139             memcpy(buffer, msg_loc, max_nbytes);
    140             msgq->read_offset = (msgq->read_offset + 1) % msgq->max_msgs;
    141             msgq->num_msgs--;
    142             pthread_mutex_unlock(&(msgq->mutex));
    143         }
    144     }
    145     return result;
    146 }
    147 
    148 int msgQNumMsgs(msg_q_id msgQ) {
    149     _msgq_hdr_t *msgq = (msg_q_id) msgQ;
    150     int num_msgs = -1;
    151 
    152     if (msgq) {
    153         pthread_mutex_lock(&(msgq->mutex));
    154         num_msgs = msgq->num_msgs;
    155         pthread_mutex_unlock(&(msgq->mutex));
    156     }
    157     return num_msgs;
    158 }