142 lines
3.7 KiB
C
142 lines
3.7 KiB
C
/***************************************************************************
|
|
* Copyright (C) 2021 - 2023 by Alessio Caiazza IU5BON *
|
|
* *
|
|
* 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 3 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, see <http://www.gnu.org/licenses/> *
|
|
***************************************************************************/
|
|
|
|
#include "chan.h"
|
|
#include <pthread.h>
|
|
|
|
void chan_init(chan_t *c)
|
|
{
|
|
if (c == NULL) return;
|
|
|
|
pthread_mutex_init(&c->m_meta, NULL);
|
|
pthread_mutex_init(&c->m_read, NULL);
|
|
pthread_mutex_init(&c->m_write, NULL);
|
|
|
|
pthread_cond_init(&c->c_reader, NULL);
|
|
pthread_cond_init(&c->c_writer, NULL);
|
|
|
|
c->reader = false;
|
|
c->writer = false;
|
|
c->closed = false;
|
|
}
|
|
|
|
void chan_send(chan_t *c, void *data)
|
|
{
|
|
pthread_mutex_lock(&c->m_write);
|
|
pthread_mutex_lock(&c->m_meta);
|
|
|
|
if (c->closed)
|
|
{
|
|
pthread_mutex_unlock(&c->m_meta);
|
|
pthread_mutex_unlock(&c->m_write);
|
|
|
|
return;
|
|
}
|
|
|
|
c->data = data;
|
|
c->writer = true;
|
|
|
|
// notify the waiting reader that data is ready
|
|
if (c->reader)
|
|
{
|
|
pthread_cond_signal(&c->c_writer);
|
|
}
|
|
|
|
// wait until data is consumed
|
|
pthread_cond_wait(&c->c_reader, &c->m_meta);
|
|
c->writer = false;
|
|
|
|
pthread_mutex_unlock(&c->m_meta);
|
|
pthread_mutex_unlock(&c->m_write);
|
|
}
|
|
|
|
void chan_recv(chan_t *c, void **data)
|
|
{
|
|
pthread_mutex_lock(&c->m_read);
|
|
pthread_mutex_lock(&c->m_meta);
|
|
|
|
// wait for a writer
|
|
while (!c->closed && !c->writer)
|
|
{
|
|
c->reader = true;
|
|
pthread_cond_wait(&c->c_writer, &c->m_meta);
|
|
c->reader = false;
|
|
}
|
|
|
|
if (c->closed)
|
|
{
|
|
pthread_mutex_unlock(&c->m_meta);
|
|
pthread_mutex_unlock(&c->m_read);
|
|
|
|
return;
|
|
}
|
|
|
|
if (data != NULL)
|
|
{
|
|
*data = c->data;
|
|
}
|
|
|
|
// notify the waiting writer that the reader consumed the data
|
|
pthread_cond_signal(&c->c_reader);
|
|
|
|
pthread_mutex_unlock(&c->m_meta);
|
|
pthread_mutex_unlock(&c->m_read);
|
|
}
|
|
|
|
|
|
bool chan_can_recv(chan_t *c)
|
|
{
|
|
pthread_mutex_lock(&c->m_meta);
|
|
bool can_receive = c->writer;
|
|
pthread_mutex_unlock(&c->m_meta);
|
|
|
|
return can_receive;
|
|
}
|
|
|
|
bool chan_can_send(chan_t *c)
|
|
{
|
|
pthread_mutex_lock(&c->m_meta);
|
|
bool can_send = c->reader;
|
|
pthread_mutex_unlock(&c->m_meta);
|
|
|
|
return can_send;
|
|
}
|
|
|
|
void chan_close(chan_t *c)
|
|
{
|
|
pthread_mutex_lock(&c->m_meta);
|
|
if (!c->closed)
|
|
{
|
|
c->closed = true;
|
|
pthread_cond_broadcast(&c->c_reader);
|
|
pthread_cond_broadcast(&c->c_writer);
|
|
}
|
|
pthread_mutex_unlock(&c->m_meta);
|
|
}
|
|
|
|
void chan_terminate(chan_t *c)
|
|
{
|
|
chan_close(c);
|
|
|
|
pthread_mutex_destroy(&c->m_write);
|
|
pthread_mutex_destroy(&c->m_read);
|
|
pthread_mutex_destroy(&c->m_meta);
|
|
|
|
pthread_cond_destroy(&c->c_writer);
|
|
pthread_cond_destroy(&c->c_reader);
|
|
}
|