/* * Usurpation – null (stdio) im proto * * Copyright (C) 2019 Gediminas Jakutis * Copyright (C) 2019 Paulius Ratkevičius * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; version 2.1 * of the License. * * 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 * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ #include #include "proto_stdio.h" #include "proto_stdio_private.h" void message_receive(char *arg) { int cancelstate; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancelstate); pthread_mutex_lock(&state.out_m); state.writebuf = strdup(arg); pthread_mutex_unlock(&state.out_m); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &cancelstate); pthread_testcancel(); nanosleep(&respite, NULL); } char *message_send(void) { char *ret = NULL; int cancelstate; pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancelstate); pthread_mutex_lock(&state.out_m); if (state.readbuf) { ret = strdup(state.readbuf); free(state.readbuf); state.readbuf = NULL; state.readbufsize = 0; } pthread_mutex_unlock(&state.out_m); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &cancelstate); pthread_testcancel(); return ret; } static void *read_stdin(void *arg) { int cancelstate; (void) arg; while(1) { pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancelstate); pthread_mutex_lock(&state.in_m); if (!state.readbuf) { state.readbufsize = getline(&state.readbuf, NULL, stdin); } pthread_mutex_unlock(&state.in_m); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &cancelstate); pthread_testcancel(); nanosleep(&respite, NULL); } return NULL; } static void *write_stdout(void *arg) { int cancelstate; (void) arg; while(1) { pthread_setcancelstate(PTHREAD_CANCEL_DISABLE, &cancelstate); pthread_mutex_lock(&state.out_m); if (state.writebuf) { if (state.writebuf[strlen(state.writebuf) - 1] == '\n') { printf("%s", state.writebuf); } else { printf("%s\n", state.writebuf); } free(state.writebuf); state.writebuf = NULL; state.writebufsize = 0; } pthread_mutex_unlock(&state.out_m); pthread_setcancelstate(PTHREAD_CANCEL_ENABLE, &cancelstate); pthread_testcancel(); nanosleep(&respite, NULL); } return NULL; } int proto_stdio_init(void) { int ret = 0; /* aquire the """singleton""" mutex */ if (pthread_mutex_trylock(&state.mutex)) { /* TODO: use proper error numbers */ ret = 1; } else { if ((ret = pthread_create(&state.stdio_in, NULL, read_stdin, NULL))) { proto_stdio_close(); } if ((ret = pthread_create(&state.stdio_out, NULL, write_stdout, NULL))) { proto_stdio_close(); } } return ret; } void proto_stdio_close(void) { int status; status = pthread_mutex_trylock(&state.mutex); if (status == EBUSY) { pthread_cancel(state.stdio_in); pthread_cancel(state.stdio_out); pthread_join(state.stdio_in, NULL); pthread_join(state.stdio_out, NULL); } else if (!status) { pthread_mutex_unlock(&state.mutex); } }