upiwin/src/msg_queue.c

124 lines
3.3 KiB
C

/*
* UPIWIN - Micro Pi Windowing Framework Kernel
* Copyright (C) 2019 Amy Bowersox/Erbosoft Metaverse Design Solutions
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*-------------------------------------------------------------------------
*/
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#include "wintype.h"
#include "time_func.h"
#include "msg_queue.h"
PMSG_QUEUE Mq_alloc(UINT32 nentries)
{
int sz = sizeof(MSG_QUEUE) + (nentries * sizeof(MSG));
PMSG_QUEUE rc;
rc = (PMSG_QUEUE)malloc(sz);
if (!rc)
return NULL;
memset(rc, 0, sz);
rc->startbound = &(rc->messagestore[0]);
rc->endbound = rc->startbound + nentries;
rc->head = rc->tail = rc->startbound;
rc->nentries = nentries;
pthread_mutex_init(&(rc->mutex), NULL);
return rc;
}
void Mq_destroy(PMSG_QUEUE queue)
{
pthread_mutex_destroy(&(queue->mutex));
free(queue);
}
static void post_internal(PMSG_QUEUE queue, PMSG msg)
{
PMSG nexttail;
pthread_mutex_lock(&(queue->mutex));
nexttail = queue->tail + 1;
if (nexttail == queue->endbound)
nexttail = queue->startbound;
if (nexttail != queue->head)
{
memcpy(queue->tail, msg, sizeof(MSG));
queue->tail = nexttail;
}
/* else drop the message silently */
pthread_mutex_unlock(&(queue->mutex));
}
void Mq_post(PMSG_QUEUE queue, HANDLE target, UINT32 message, const UINT_PTR *attrs, int nattrs)
{
MSG tmpmsg;
memset(&tmpmsg, 0, sizeof(MSG));
tmpmsg.target = target;
tmpmsg.message = message;
if (nattrs > MSG_ATTRCOUNT)
nattrs = MSG_ATTRCOUNT;
if (nattrs > 0)
memcpy(&(tmpmsg.attrs), attrs, sizeof(UINT_PTR) * nattrs);
tmpmsg.timestamp = Time_since_start();
post_internal(queue, &tmpmsg);
}
void Mq_post2(PMSG_QUEUE queue, HANDLE target, UINT32 message, UINT_PTR attr1, UINT_PTR attr2)
{
MSG tmpmsg;
memset(&tmpmsg, 0, sizeof(MSG));
tmpmsg.target = target;
tmpmsg.message = message;
tmpmsg.attrs[0] = attr1;
tmpmsg.attrs[1] = attr2;
tmpmsg.timestamp = Time_since_start();
post_internal(queue, &tmpmsg);
}
BOOL Mq_peek(PMSG_QUEUE queue, PMSG msg, UINT32 flags)
{
BOOL rc = FALSE;
PMSG nexthead;
pthread_mutex_lock(&(queue->mutex));
if (queue->head != queue->tail)
{
nexthead = queue->head + 1;
if (nexthead == queue->endbound)
nexthead = queue->startbound;
memcpy(msg, queue->head, sizeof(MSG));
if (flags & PEEK_REMOVE)
queue->head = nexthead;
rc = TRUE;
}
pthread_mutex_unlock(&(queue->mutex));
return rc;
}
BOOL Mq_is_empty(PMSG_QUEUE queue)
{
BOOL rc;
pthread_mutex_lock(&(queue->mutex));
rc = (queue->head == queue->tail);
pthread_mutex_unlock(&(queue->mutex));
return rc;
}