I got two threads (thrd_t
): one main thread processing events
and one child thread waiting for terminal input using fgetwc
.
#include <threads.h> // mtx_t, mtx_lock, mtx_unlock
#include <wchar.h> // fgetwc, fgetwc_unlocked
FILE* f = (FILE*) p2;
mtx_t* m = (mtx_t*) p1;
volatile sig_atomic_t* i = (volatile sig_atomic_t*) p0;
mtx_lock(m);
volatile wint_t c = fgetwc(f);
if (c != WEOF) {
ungetwc(c, f);
copy_integer(p0, (void*) TRUE_BOOLEAN_STATE_CYBOI_MODEL);
}
mtx_unlock(m);
while (*i != *FALSE_BOOLEAN_STATE_CYBOI_MODEL);
Since I want to read ansi escape code sequences (three characters),
the terminal must not block after each character and is therefore
set to non-blocking in the main thread using t.c_cc[VMIN]=0
.
After the sequence has been detected, I reset the terminal to blocking
using t.c_cc[VMIN]=1
, so that the child thread blocks at fgetwc
until the next input gets detected.
mtx_t* m = (mtx_t*) p3;
int* i = (int*) p2;
// The loop break flag.
int b = *FALSE_BOOLEAN_STATE_CYBOI_MODEL;
// The escape character flag.
int esc = *FALSE_BOOLEAN_STATE_CYBOI_MODEL;
int aec = *FALSE_BOOLEAN_STATE_CYBOI_MODEL;
// The input character.
wint_t c = WEOF;
mtx_lock(m);
// Set unblocking mode in terminal.
edit_service(p4, (void*) FALSE_BOOLEAN_STATE_CYBOI_MODEL, (void*) FALSE_BOOLEAN_STATE_CYBOI_MODEL, (void*) FALSE_BOOLEAN_STATE_CYBOI_MODEL, (void*) TERMINAL_CYBOI_CHANNEL);
while (*TRUE_BOOLEAN_STATE_CYBOI_MODEL) {
if (b != *FALSE_BOOLEAN_STATE_CYBOI_MODEL) {
break;
}
read_unix_terminal_character(p0, p1, (void*) &b, (void*) &esc, (void*) &aec, (void*) &c);
}
// Set blocking mode in terminal. VMIN = 1
edit_service(p4, (void*) TRUE_BOOLEAN_STATE_CYBOI_MODEL, (void*) FALSE_BOOLEAN_STATE_CYBOI_MODEL, (void*) FALSE_BOOLEAN_STATE_CYBOI_MODEL, (void*) TERMINAL_CYBOI_CHANNEL);
// Reset interrupt request in input/output entry.
copy_integer(i, (void*) FALSE_BOOLEAN_STATE_CYBOI_MODEL);
mtx_unlock(m);
Problem: Sometimes, fgetwc
blocks, other times it does not.
When a character sequence was read in (three characters),
the reading loop is left at the third character and
the child thread blocks fine.
When a single character is read, then its end gets detected by a
following WEOF
, but the child thread does not block anymore,
even though t.c_cc[VMIN]=1
.
wint_t* c = (wint_t*) p5;
int* aec = (int*) p4;
int* esc = (int*) p3;
FILE* f = (FILE*) p1;
*c = fgetwc(f);
if (*c != WEOF) {
if (*aec == *TRUE_BOOLEAN_STATE_CYBOI_MODEL) {
// The character sequence ESC[ was received before.
// This is the beginning of an ansi escape code sequence.
// Reset ansi escape code flag.
copy_integer(p4, (void*) FALSE_BOOLEAN_STATE_CYBOI_MODEL);
// Append source character to destination item.
// This is the actual ansi escape code.
modify_item(p0, p5, (void*) WIDE_CHARACTER_TEXT_STATE_CYBOI_TYPE, (void*) FALSE_BOOLEAN_STATE_CYBOI_MODEL, (void*) PRIMITIVE_STATE_CYBOI_MODEL_COUNT, *NULL_POINTER_STATE_CYBOI_MODEL, (void*) VALUE_PRIMITIVE_STATE_CYBOI_NAME, (void*) TRUE_BOOLEAN_STATE_CYBOI_MODEL, (void*) APPEND_MODIFY_LOGIC_CYBOI_FORMAT);
// Set loop break flag.
// All values have been received, so that the loop can be left now.
copy_integer(p2, (void*) TRUE_BOOLEAN_STATE_CYBOI_MODEL);
} else if (*esc == *TRUE_BOOLEAN_STATE_CYBOI_MODEL) {
// The escape character ESC was received before.
// This might be the beginning of an ansi escape code.
// Reset escape character flag.
copy_integer(p3, (void*) FALSE_BOOLEAN_STATE_CYBOI_MODEL);
if (*c == *((wint_t*) LEFT_SQUARE_BRACKET_UNICODE_CHARACTER_CODE_MODEL)) {
// The escape character ESC received before
// is followed by an opening square bracket [.
// This is the beginning of an ansi escape code.
// Set ansi escape code flag.
copy_integer(p4, (void*) TRUE_BOOLEAN_STATE_CYBOI_MODEL);
// Append source character to destination item.
modify_item(p0, p5, (void*) WIDE_CHARACTER_TEXT_STATE_CYBOI_TYPE, (void*) FALSE_BOOLEAN_STATE_CYBOI_MODEL, (void*) PRIMITIVE_STATE_CYBOI_MODEL_COUNT, *NULL_POINTER_STATE_CYBOI_MODEL, (void*) VALUE_PRIMITIVE_STATE_CYBOI_NAME, (void*) TRUE_BOOLEAN_STATE_CYBOI_MODEL, (void*) APPEND_MODIFY_LOGIC_CYBOI_FORMAT);
} else {
// The escape character ESC received before
// is followed by another, second character
// which is NOT an opening square bracket.
// This is NOT going to be an ansi escape code sequence.
// Unread this character so that it may be
// processed once more later on.
ungetwc(*c, f);
// Set loop break flag.
copy_integer(p2, (void*) TRUE_BOOLEAN_STATE_CYBOI_MODEL);
}
} else if (*c == *((wint_t*) ESCAPE_UNICODE_CHARACTER_CODE_MODEL)) {
// The escape character ESC was received.
// This might be the beginning of an ansi escape code.
// Set escape character flag.
copy_integer(p3, (void*) TRUE_BOOLEAN_STATE_CYBOI_MODEL);
// Copy source character to destination character array.
modify_item(p0, p5, (void*) WIDE_CHARACTER_TEXT_STATE_CYBOI_TYPE, (void*) FALSE_BOOLEAN_STATE_CYBOI_MODEL, (void*) PRIMITIVE_STATE_CYBOI_MODEL_COUNT, *NULL_POINTER_STATE_CYBOI_MODEL, (void*) VALUE_PRIMITIVE_STATE_CYBOI_NAME, (void*) TRUE_BOOLEAN_STATE_CYBOI_MODEL, (void*) APPEND_MODIFY_LOGIC_CYBOI_FORMAT);
} else {
// No special characters have been found.
// So this is a normal source character
// that is just copied to the destination.
// Copy source character to destination character array.
modify_item(p0, p5, (void*) WIDE_CHARACTER_TEXT_STATE_CYBOI_TYPE, (void*) FALSE_BOOLEAN_STATE_CYBOI_MODEL, (void*) PRIMITIVE_STATE_CYBOI_MODEL_COUNT, *NULL_POINTER_STATE_CYBOI_MODEL, (void*) VALUE_PRIMITIVE_STATE_CYBOI_NAME, (void*) TRUE_BOOLEAN_STATE_CYBOI_MODEL, (void*) APPEND_MODIFY_LOGIC_CYBOI_FORMAT);
// CAUTION! Do NOT set loop break flag here.
// More than just one character might have to be
// received in a sequence, e.g. an ansi escape code.
// In this case, only a WEOF will break the loop.
}
} else {
// Set loop break flag.
copy_integer(p2, (void*) TRUE_BOOLEAN_STATE_CYBOI_MODEL);
}
Is the termios c_cc[VMIN] value possibly cached and not read from shared memory?
Find the project and all source code here: https://savannah.nongnu.org/svn/?group=cybop
Possibly related: Does making reference variable volatile, make all its field volatile too in java? "... objects are not variables. ... all threads see the same reference, not that they observe the same values for its inner content."