Schedule an asynchronous event that will complete when stdin has waiting data in boost::asio? - select

I'm using boost::asio with ncurses for a command-line game. The game needs to draw on the screen at a fixed time interval, and other operations (e.g. networking or file operations) are also executed whenever necessary. All these things can be done with async_read()/async_write() or equivalent on boost::asio.
However, I also need to read keyboard input, which (I think) comes from stdin. The usual way to read input in ncurses is to call getch(), which can be configured to either blocking (wait until there is a character available for consumption) or non-blocking (return a sentinel value of there no characters available) mode.
Using blocking mode would necessitate running getch() on a separate thread, which doesn't play well with ncurses. Using non-blocking mode, however, would cause my application to consume CPU time spinning in a loop until the user presses their keyboard. I've read this answer, which suggests that we can add stdin to the list of file descriptors in a select() call, which would block until one of the file descriptors has new data.
Since I'm using boost::asio, I can't directly use select(). I can't call async_read, because that would consume the character, leaving getch() with nothing to read. Is there something in boost::asio like async_read, but merely checks the existence of input without consuming it?

I think you should be able to use the posix stream descriptor to watch for input on file descriptor 0:
ba::posix::stream_descriptor d(io, 0);
input_loop = [&](error_code ec) {
if (!ec) {
program.on_input();
d.async_wait(ba::posix::descriptor::wait_type::wait_read, input_loop);
}
};
There, program::on_input() would call getch() with no timeout() until it returns ERR:
struct Program {
Program() {
initscr();
ESCDELAY = 0;
timeout(0);
cbreak();
noecho();
keypad(stdscr, TRUE); // receive special keys
clock = newwin(2, 40, 0, 0);
monitor = newwin(10, 40, 2, 0);
syncok(clock, true); // automatic updating
syncok(monitor, true);
scrollok(monitor, true); // scroll the input monitor window
}
~Program() {
delwin(monitor);
delwin(clock);
endwin();
}
void on_clock() {
wclear(clock);
char buf[32];
time_t t = time(NULL);
if (auto tmp = localtime(&t)) {
if (strftime(buf, sizeof(buf), "%T", tmp) == 0) {
strncpy(buf, "[error formatting time]", sizeof(buf));
}
} else {
strncpy(buf, "[error getting time]", sizeof(buf));
}
wprintw(clock, "Async: %s", buf);
wrefresh(clock);
}
void on_input() {
for (auto ch = getch(); ch != ERR; ch = getch()) {
wprintw(monitor, "received key %d ('%c')\n", ch, ch);
}
wrefresh(monitor);
}
WINDOW *monitor = nullptr;
WINDOW *clock = nullptr;
};
With the following main program you'd run it for 10 seconds (because Program doesn't yet know how to exit):
int main() {
Program program;
namespace ba = boost::asio;
using boost::system::error_code;
using namespace std::literals;
ba::io_service io;
std::function<void(error_code)> input_loop, clock_loop;
// Reading input when ready on stdin
ba::posix::stream_descriptor d(io, 0);
input_loop = [&](error_code ec) {
if (!ec) {
program.on_input();
d.async_wait(ba::posix::descriptor::wait_type::wait_read, input_loop);
}
};
// For fun, let's also update the time
ba::high_resolution_timer tim(io);
clock_loop = [&](error_code ec) {
if (!ec) {
program.on_clock();
tim.expires_from_now(100ms);
tim.async_wait(clock_loop);
}
};
input_loop(error_code{});
clock_loop(error_code{});
io.run_for(10s);
}
This works:
Full Listing
#include <boost/asio.hpp>
#include <boost/asio/posix/descriptor.hpp>
#include <iostream>
#include "ncurses.h"
#define CTRL_R 18
#define CTRL_C 3
#define TAB 9
#define NEWLINE 10
#define RETURN 13
#define ESCAPE 27
#define BACKSPACE 127
#define UP 72
#define LEFT 75
#define RIGHT 77
#define DOWN 80
struct Program {
Program() {
initscr();
ESCDELAY = 0;
timeout(0);
cbreak();
noecho();
keypad(stdscr, TRUE); // receive special keys
clock = newwin(2, 40, 0, 0);
monitor = newwin(10, 40, 2, 0);
syncok(clock, true); // automatic updating
syncok(monitor, true);
scrollok(monitor, true); // scroll the input monitor window
}
~Program() {
delwin(monitor);
delwin(clock);
endwin();
}
void on_clock() {
wclear(clock);
char buf[32];
time_t t = time(NULL);
if (auto tmp = localtime(&t)) {
if (strftime(buf, sizeof(buf), "%T", tmp) == 0) {
strncpy(buf, "[error formatting time]", sizeof(buf));
}
} else {
strncpy(buf, "[error getting time]", sizeof(buf));
}
wprintw(clock, "Async: %s", buf);
wrefresh(clock);
}
void on_input() {
for (auto ch = getch(); ch != ERR; ch = getch()) {
wprintw(monitor, "received key %d ('%c')\n", ch, ch);
}
wrefresh(monitor);
}
WINDOW *monitor = nullptr;
WINDOW *clock = nullptr;
};
int main() {
Program program;
namespace ba = boost::asio;
using boost::system::error_code;
using namespace std::literals;
ba::io_service io;
std::function<void(error_code)> input_loop, clock_loop;
// Reading input when ready on stdin
ba::posix::stream_descriptor d(io, 0);
input_loop = [&](error_code ec) {
if (!ec) {
program.on_input();
d.async_wait(ba::posix::descriptor::wait_type::wait_read, input_loop);
}
};
// For fun, let's also update the time
ba::high_resolution_timer tim(io);
clock_loop = [&](error_code ec) {
if (!ec) {
program.on_clock();
tim.expires_from_now(100ms);
tim.async_wait(clock_loop);
}
};
input_loop(error_code{});
clock_loop(error_code{});
io.run_for(10s);
}

Related

S-function Level 2 C Simulink (R2006b) , Getting string from parameter

I don't find the way to get the string specified in the dialog box of an S-function (C, level 2) block and save it in a variable, inside the .c file corresponding to the block.
Through *mxGetPr(ssGetSFcnParam(S, 0)) I can only get the first position value in the string.
The parameter entered in the dialog block what it is related to the ssGetSFcnParam(S, 0) is '123'.
In the mask editor of the block the type is 'edit'.
#define S_FUNCTION_NAME ver_file_data
#define S_FUNCTION_LEVEL 2
#define NPARAMS 14
#define DVC_TYPE(S) ssGetSFcnParam(S, 0)
static void mdlInitializeSizes(SimStruct *S){
DECL_AND_INIT_DIMSINFO(outputDimsInfo);
ssSetNumSFcnParams(S, NPARAMS); /* Number of expected parameters */
ssSetSFcnParamTunable(S, 0, 0);
ssSetSFcnParamTunable(S, 1, 0);
#if defined(MATLAB_MEX_FILE) if (ssGetNumSFcnParams(S) == ssGetSFcnParamsCount(S)) {
mdlCheckParameters(S);
if (ssGetErrorStatus(S) != NULL) {
return;
} } else {
return; }
#endif
ssSetNumContStates(S, 0);
ssSetNumDiscStates(S, 0);
if (!ssSetNumInputPorts(S, NUM_INPUTS)) return;
if (!ssSetNumOutputPorts(S, NUM_OUTPUTS)) return;
/* Output Port 0 */
ssSetOutputPortWidth(S, 0, 1);
ssSetOutputPortDataType(S, 0, SS_UINT8);
ssSetNumSampleTimes(S, 1);
ssSetNumRWork(S, 0);
ssSetNumIWork(S, 0);
ssSetNumPWork(S, 0);
ssSetNumModes(S, 0);
ssSetNumNonsampledZCs(S, 0);
}
static void mdlInitializeSampleTimes(SimStruct *S){
ssSetSampleTime(S, 0, -1);
ssSetOffsetTime(S, 0, 0.0);
}
static void mdlOutputs(SimStruct *S, int_T tid){
ssPrintf("DVC_IND_NO = %x\n",*mxGetPr(DVC_IND_NO(S)));
}
mdlRTW (SimStruct *S){
}
Before getting anything through the outputport, I would like to be able to print with ssPrintf("DVC_IND_NO = %x\n",*mxGetPr(DVC_IND_NO(S))); the 123.
Thank you, best regards.
mxGetPr returns a pointer to double, so makes no sense if the parameter is a char array. And in using *mxGetPr you are saying that you want the value that is pointed to (i.e. the first element, if it is a multi-element double array), which is why you are only getting the first value.
If the input is expected to be a string (i.e. array of char) then you should be using mxArrayToString to access it.
Either way, you should definitely be using helper functions like mxIsChar and mxIsDouble to check the data type before using the appropriate function to access the data.
Add the following at the top
#define DVC_IND_NO(S) = ssGetSFcnParam(S,0)
and the follwoing in your mdlOutputs
char* str;
int i = 0;
str = mxArrayToString(DVC_IND_NO(S));
ssPrintf("DVC_IND_NO = ");
while (str[i]!='\0')
{
ssPrintf("%c",str[i]);
i++;
}

Why does XGrabKey return BadRequest?

So I'm working on a Gtk/X11/Linux app that does screen capture to .gif and one of the methods of stopping the capture is a key press (Esc, Space or End). You can also use a timeout. However to implement the key press to end capture I have to be able to grab the key such that I can get an event even though my window doesn't have focus (it's actually invisible during capture). I believe XGrabKey is the right X11 function for this task:
Window w = Gtk::gdk_x11_drawable_get_xid(Gtk::gtk_widget_get_window(Handle()));
KeyCode kc = XKeysymToKeycode(Gtk::gdk_display, HotKeyCode);
int r = XGrabKey( Gtk::gdk_display,
kc,
0 /* modifiers */,
w /* grab_window */,
TRUE /* owner_events */,
GrabModeAsync /* pointer_mode */,
GrabModeAsync /* keyboard_mode */);
printf("XGrabKey(%p, 0x%x/%x)=%i\n", w, HotKeyCode, kc, r);
Where 'HotKeyCode' is say XK_Escape or something e.g.:
XGrabKey(0x3e00003, 0xff1b/9)=1
XGrabKey is returning '1' or BadRequest. What am I doing wrong here?
FYI the actual Xorg Xserver code in question appears to be here.
Edit: The latest incarnation of the code is:
int x_err_callback(Display *d, XErrorEvent *e)
{
char msg[256];
XGetErrorText(d, e->error_code, msg, sizeof(msg));
printf("X11Error %d (%s): request %d.%d\n",
e->error_code, msg, e->request_code,
e->minor_code);
return 0;
}
Gtk::GdkFilterReturn key_filter(Gtk::GdkXEvent *gdk_xevent,
Gtk::GdkEvent *event,
Gtk::gpointer data)
{
XKeyEvent *xevent = gdk_xevent;
if (xevent->type == KeyPress)
{
int key = ((XKeyEvent *)gdk_xevent)->keycode;
int keysym = XKeycodeToKeysym(Gtk::gdk_display, key, 0);
printf("caught keysym %i\n", keysym);
switch (keysym)
{
case 1: // your_keysym
// your key handler code
break;
}
}
return Gtk::GDK_FILTER_CONTINUE;
}
Gtk::GdkWindow *Root = Gtk::gdk_get_default_root_window();
KeyCode kc = XKeysymToKeycode(Gtk::gdk_display, HotKeyCode);
XSetErrorHandler(x_err_callback);
int r = XGrabKey( Gtk::gdk_display,
kc,
AnyModifier /* modifiers */,
GDK_WINDOW_XWINDOW(Root) /* grab_window */,
TRUE /* owner_events */,
GrabModeAsync /* pointer_mode */,
GrabModeSync /* keyboard_mode */);
Gtk::gdk_window_set_events(Root,
(Gtk::GdkEventMask)
(Gtk::GDK_KEY_PRESS_MASK |
Gtk::GDK_KEY_RELEASE_MASK));
Gtk::gdk_window_add_filter(NULL, key_filter, this);
AnyModifier actually results in an error. '0' doesn't. I know about the NumLock issue...
A return value of 1 does not mean that a BadRequest error occured. Xlib handles errors via an error handler, and the function will always return 1, if it returns at all.
Your code does not work because you have to do the XGrabKey on the root window (GetDefaultRootWindow(Gtk::gdk_display)). Here's a pure Xlib demo:
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <stdio.h>
int main() {
Display *d = XOpenDisplay(0);
Window root = DefaultRootWindow(d);
int keycode = XKeysymToKeycode(d, XK_BackSpace);
int rv = XGrabKey(d, keycode, AnyModifier, root, 1, GrabModeAsync, GrabModeAsync);
printf("XGrabKey returned %d\n", rv);
XEvent evt;
while(1) {
XNextEvent(d, &evt);
printf("Got event %d\n", evt.type);
}
}
To then capture the X11 events from GTK use gdk_window_add_filter on a NULL or on the root window and a GdkFilterFunc that processes the events associated with your global hotkey:
#include <X11/Xlib.h>
#include <X11/keysym.h>
#include <gtk/gtk.h>
#include <gdk/gdkx.h>
#include <stdio.h>
GdkFilterReturn filter(GdkXEvent *xevent, GdkEvent *event, gpointer data) {
XKeyEvent *ev = (XKeyEvent *)xevent;
if(ev->type == 2) {
printf("Backspace hit.\n");
}
return GDK_FILTER_CONTINUE;
}
int main(int argc, char *argv[]) {
gtk_init(&argc, &argv);
GdkScreen *scr = gdk_screen_get_default();
GdkWindow *groot = gdk_screen_get_root_window(scr);
gdk_window_set_events(groot, GDK_KEY_PRESS_MASK);
gdk_window_add_filter(groot, filter, NULL);
Display *d = gdk_x11_get_default_xdisplay();
Window root = GDK_WINDOW_XID(groot);
int keycode = XKeysymToKeycode(d, XK_BackSpace);
XGrabKey(d, keycode, AnyModifier, root, 1, GrabModeAsync, GrabModeAsync);
gtk_main();
}
As a side note, a modifier mask of 0 means that no modifiers must be enabled, even those that would not modify the meaning of a key. A grab on the letter "A" with a 0 modifier would not match NumLock + A. That's why I used AnyModifer.

GPS output being incorrectly written to file on SD card- Arduino

I have a sketch to take information (Lat, Long) from an EM-406a GPS receiver and write the information to an SD card on an Arduino shield.
The program is as follows:
#include <TinyGPS++.h>
#include <SoftwareSerial.h>
#include <SD.h>
TinyGPSPlus gps;
SoftwareSerial ss(4, 3); //pins for the GPS
Sd2Card card;
SdVolume volume;
SdFile root;
SdFile file;
void setup()
{
Serial.begin(115200); //for the serial output
ss.begin(4800); //start ss at 4800 baud
Serial.println("gpsLogger by Aaron McRuer");
Serial.println("based on code by Mikal Hart");
Serial.println();
//initialize the SD card
if(!card.init(SPI_FULL_SPEED, 9))
{
Serial.println("card.init failed");
}
//initialize a FAT volume
if(!volume.init(&card)){
Serial.println("volume.init failed");
}
//open the root directory
if(!root.openRoot(&volume)){
Serial.println("openRoot failed");
}
//create new file
char name[] = "WRITE00.TXT";
for (uint8_t i = 0; i < 100; i++){
name[5] = i/10 + '0';
name[6] = i%10 + '0';
if(file.open(&root, name, O_CREAT | O_EXCL | O_WRITE)){
break;
}
}
if(!file.isOpen())
{
Serial.println("file.create");
}
file.print("Ready...\n");
}
void loop()
{
bool newData = false;
//For one second we parse GPS data and report some key values
for (unsigned long start = millis(); millis() - start < 1000;)
{
while (ss.available())
{
char c = ss.read();
//Serial.write(c); //uncomment this line if you want to see the GPS data flowing
if(gps.encode(c)) //did a new valid sentence come in?
newData = true;
}
}
if(newData)
{
file.write(gps.location.lat());
file.write("\n");
file.write(gps.location.lng());
file.write("\n");
}
file.close();
}
When I open up the file on the SD card when the program is finished executing, I get a message that it has an encoding error.
I'm currently inside (and unable to get a GPS signal, thus the 0), but the encoding problem needs to be tackled, and there should be as many lines as there are seconds that the device has been on. There's only that one. What do I need to do to make things work correctly here?
Closing the file in the loop, and never reopening it, is the reason there's only one set of data in your file.
Are you sure gps.location.lat() and gps.location.lng() return strings, not an integer or float? That would explain the binary data and the "encoding error" you see.

ncurses interrupts system call when resizing terminal

I have a problem with ncurses and couldn't find a solution on the web, so I've written following little program to demonstrate the problem.
You can compile it via:
sudo aptitude install ncurses-dev
g++ -lncurses -o resize resize.cpp
It displays an integer counter incremented every second by forking into a timer process which periodically sends one byte to the parent process via a socketpair. You can quit it by pressing CTRL+C.
When you resize the terminal you should get an error message of 'Interrupted system call'. So the read call gets interrupted by SIGWINCH when resizing. But how can I avoid this? Or is it common that the system call gets interrupted? But how would I handle an interrupted system call in order to proceed incrementing the counter since the file descripter appears to be dead after interruption.
If you use non-blocking sockets, you would get 'Resource temporarily unavailable' instead.
I am using stable debian wheezy, so the ncurses version is 5.9-10 and the libstdc++ version is 4.7.2-5.
#include <ncurses.h>
#include <signal.h>
#include <netdb.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <string>
#include <iostream>
//Define a second.
timespec span = {1, 0};
//Handles both, SIGWINCH and SIGINT
void handle(int signal) {
switch (signal) {
case SIGWINCH:
//Reinitialize ncurses to get new size
endwin();
refresh();
printw("Catched SIGWINCH and handled it.\n");
refresh();
break;
case SIGINT:
//Catched CTRL+C and quit
endwin();
exit(0);
break;
}
}
//This registers above signal handler function
void set_handler_for(int signal) {
struct sigaction action;
action.sa_handler = handle;
action.sa_flags = 0;
if (-1 == sigemptyset(&action.sa_mask) or -1 == sigaction(signal, &action, NULL))
throw "Cannot set signal handler";
}
main() {
int fd[2];
//In this try block we fork into the timer process
try {
set_handler_for(SIGINT);
set_handler_for(SIGWINCH);
//Creating a socketpair to communicate between timer and parent process
if (-1 == socketpair(PF_LOCAL, SOCK_STREAM, 0, fd))
throw "Cannot create socketpair";
pid_t pid;
//Doing the fork
if (-1 == (pid = fork()))
throw "Cannot fork process";
if (!pid) {
//We are the timer, so closing the other end of the socketpair
close(fd[0]);
//We send one byte every second to the parent process
while (true) {
char byte;
ssize_t bytes = write(fd[1], &byte, sizeof byte);
if (0 >= bytes)
throw "Cannot write";
nanosleep(&span, 0);
}
//Here the timer process ends
exit(0);
}
//We are the parent process, so closing the other end of the socketpair
close(fd[1]);
}
catch (const char*& what) {
std::cerr << what << std::endl;
exit(1);
}
//Parent process - Initializing ncurses
initscr();
noecho();
curs_set(0);
nodelay(stdscr, TRUE);
//In this try block we read (blocking) the byte from the timer process every second
try {
int tick = 0;
while (true) {
char byte;
ssize_t bytes = read(fd[0], &byte, sizeof byte);
if (0 >= bytes)
throw "Cannot read";
//Clear screen and print increased counter
clear();
mvprintw(0, 0, "Tick: %d - Resize terminal and press CTRL+C to quit.\n", ++tick);
//Catch special key KEY_RESIZE and reinitialize ncurses to get new size (actually not necassary)
int key;
while ((key = getch()) != ERR) {
if (key == KEY_RESIZE) {
endwin();
refresh();
printw("Got KEY_RESIZE and handled it.\n");
}
}
//Update the screen
refresh();
}
}
catch (const char*& what) {
//We got an error - print it but don't quit in order to have time to read it
std::string error(what);
if (errno) {
error.append(": ");
error.append(strerror(errno));
}
error = "Catched exception: "+error+"\n";
printw(error.c_str());
refresh();
//Waiting for CTRL+C to quit
while (true)
nanosleep(&span, 0);
}
}
Thank you!
Regards
Most (if not all) system calls have an interrupted error code (errno == EINTR), this is normal.
I would check for EINTR on the read from the pipe and ignore it, just read again.
I wouldn't call any ncurses functions in the signal handler, some are re-entrant but I doubt printw is. Just do the KEY_RESIZE check.
Okay, I got it working by only using re-entrant functions within signal handlers. Now the socketpair is still working after an EINTR or EAGAIN.
Thank you!
#include <ncurses.h>
#include <signal.h>
#include <netdb.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <string>
#include <iostream>
// Define a second.
timespec base = {1, 0};
// Holds raised SIGINTs.
size_t raised_SIGINT = 0;
// Holds raised SIGWINCHs.
size_t raised_SIGWINCH = 0;
// Handle SIGWINCH
void handle_SIGWINCH(int) {
++raised_SIGWINCH;
}
// Handle SIGINT
void handle_SIGINT(int) {
++raised_SIGINT;
}
// Registers signal handlers.
void assign(int signal, void (*handler)(int)) {
struct sigaction action;
action.sa_handler = handler;
action.sa_flags = 0;
if (-1 == sigemptyset(&action.sa_mask) or -1 == sigaction(signal, &action, NULL))
throw "Cannot set signal handler";
}
// Prints ticks alive and usage information.
inline void print(size_t ticks) {
mvprintw(0, 0, "%ds alive. Resize terminal and press CTRL+C to quit.\n\n", ticks);
}
int main() {
// Holds the two socketpair file descriptors.
int fd[2];
// Fork into the timer process.
try {
// Register both signals.
assign(SIGINT, handle_SIGINT);
assign(SIGWINCH, handle_SIGWINCH);
// Create a socketpair to communicate between timer and parent process.
if (-1 == socketpair(PF_LOCAL, SOCK_STREAM, 0, fd))
throw "Cannot create socketpair";
// Doing the fork.
pid_t pid;
if (-1 == (pid = fork()))
throw "Cannot fork process";
if (!pid) {
// We are the timer, so closing the parent end of the socketpair.
close(fd[0]);
// We send one byte every second to the parent process.
while (true) {
timespec less = base;
int ret;
// Continue sleeping after SIGWINCH but only for the time left.
while (-1 == (ret = nanosleep(&less, &less)) and errno == EINTR and raised_SIGWINCH);
// Maybe quit by user.
if (raised_SIGINT)
return 0;
// If something went wrong, terminate.
if (-1 == ret)
throw "Cannot sleep";
// Repeated writing if interrupted by SIGWINCH.
char byte;
ssize_t bytes;
do {
// Doing the write.
bytes = write(fd[1], &byte, sizeof byte);
}
while (0 >= bytes and (errno == EAGAIN or errno == EINTR) and raised_SIGWINCH);
// Maybe quit by user.
if (raised_SIGINT)
return 0;
// If something went wrong, terminate.
if (0 >= bytes)
throw "Cannot write";
}
// Here the timer process ends.
return 0;
}
// We are the parent process, so closing the timer end of the socketpair.
close(fd[1]);
}
catch (const char*& what) {
// Print fatal error and terminate timer process causing parent process to terminate, too.
std::cerr << what << std::endl;
return 1;
}
// Initializing ncurses for the parent process.
initscr();
// Disable typing.
noecho();
// Disable cursor.
curs_set(0);
// Make reading characters non-blocking.
nodelay(stdscr, TRUE);
// Catch fatal errors.
try {
// Holds ticks alive.
size_t ticks = 0;
// Blockingly read the byte from the timer process awaiking us every second.
while (true) {
// Print ticks alive before incrementing them.
print(ticks++);
// Holds typed keys.
std::string keys;
// Read typed keys.
for (int key = getch(); key != ERR; key = getch())
if (key != KEY_RESIZE)
keys += key;
// Format typed keys string.
if (keys.size())
printw("You've typed: ");
else
keys += "\n";
keys += "\n\n";
// Print typed keys string.
printw(keys.c_str());
// Doing the prints.
refresh();
// Repeated reading if interrupted by SIGWINCH.
ssize_t bytes = 0;
bool again = false;
do {
// Doing the read.
char byte;
bytes = read(fd[0], &byte, sizeof byte);
again = (0 >= bytes and (errno == EAGAIN or errno == EINTR) and raised_SIGWINCH);
// Print how often we got interrupted by SIGWINCH per time base.
if (again) {
// Next two calls are the common way to handle a SIGWINCH.
endwin();
refresh();
// For simpicity clear everything.
clear();
// Re-print ticks.
print(ticks);
// Print the interruption counter.
printw("%dx catched SIGWINCH per time base.\n\n", raised_SIGWINCH);
// Doing the prints.
refresh();
}
}
while (again);
// Reset SIGWINCH raises per time base.
raised_SIGWINCH = 0;
// Maybe quit by user.
if (raised_SIGINT) {
endwin();
return 0;
}
// If something went wrong, terminate.
if (0 >= bytes)
throw "Cannot read";
}
}
catch (const char*& what) {
// We got an error, appending errno if set.
std::string error(what);
if (errno) {
error.append(": ");
error.append(strerror(errno));
}
error = "Catched exception: "+error+"\n";
// Print the fatal error.
printw(error.c_str());
//Doing the print.
refresh();
// Waiting for CTRL+C to quit.
while (true)
nanosleep(&base, 0);
// Quit by user.
endwin();
return 0;
}
}

order of execution of forked processes

#include<stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<sys/sem.h>
#include<sys/ipc.h>
int sem_id;
void update_file(int number)
{
struct sembuf sem_op;
FILE* file;
printf("Inside Update Process\n");
/* wait on the semaphore, unless it's value is non-negative. */
sem_op.sem_num = 0;
sem_op.sem_op = -1; /* <-- Amount by which the value of the semaphore is to be decreased */
sem_op.sem_flg = 0;
semop(sem_id, &sem_op, 1);
/* we "locked" the semaphore, and are assured exclusive access to file. */
/* manipulate the file in some way. for example, write a number into it. */
file = fopen("file.txt", "a+");
if (file) {
fprintf(file, " \n%d\n", number);
fclose(file);
}
/* finally, signal the semaphore - increase its value by one. */
sem_op.sem_num = 0;
sem_op.sem_op = 1;
sem_op.sem_flg = 0;
semop( sem_id, &sem_op, 1);
}
void write_file(char* contents)
{
printf("Inside Write Process\n");
struct sembuf sem_op;
sem_op.sem_num = 0;
sem_op.sem_op = -1;
sem_op.sem_flg = 0;
semop( sem_id, &sem_op, 1);
FILE *file = fopen("file.txt","w");
if(file)
{
fprintf(file,contents);
fclose(file);
}
sem_op.sem_num = 0;
sem_op.sem_op = 1;
sem_op.sem_flg = 0;
semop( sem_id, &sem_op, 1);
}
int main()
{
//key_t key = ftok("file.txt",'E');
sem_id = semget( IPC_PRIVATE, 1, 0600 | IPC_CREAT);
/*here 100 is any arbit number to be assigned as the key of the
semaphore,1 is the number of semaphores in the semaphore set, */
if(sem_id == -1)
{
perror("main : semget");
exit(1);
}
int rc = semctl( sem_id, 0, SETVAL, 1);
pid_t u = fork();
if(u == 0)
{
update_file(100);
exit(0);
}
else
{
wait();
}
pid_t w = fork();
if(w == 0)
{
write_file("Hello!!");
exit(0);
}
else
{
wait();
}
}
If I run the above code as a c code, the write_file() function is called after the update_file () function
Whereas if I run the same code as a c++ code, the order of execution is reverse... why is it so??
Just some suggestions, but it looks to me like it could be caused by a combination of things:
The wait() call is supposed to take a pointer argument (that can
be NULL). Compiler should have caught this, but you must be picking
up another definition somewhere that permits your syntax. You are
also missing an include for sys/wait.h. This might be why the
compiler isn't complaining as I'd expect it to.
Depending on your machine/OS configuration the fork'd process may
not get to run until after the parent yields. Assuming the "wait()"
you are calling isn't working the way we would be expecting, it is
possible for the parent to execute completely before the children
get to run.
Unfortunately, I wasn't able to duplicate the same temporal behavior. However, when I generated assembly files for each of the two cases (C & C++), I noticed that the C++ version is missing the "wait" system call, but the C version is as I would expect. To me, this suggests that somewhere in the C++ headers this special version without an argument is being #defined out of the code. This difference could be the reason behind the behavior you are seeing.
In a nutshell... add the #include, and change your wait calls to "wait(0)"