Search code examples
clinuxpthreadsnamed-pipesncurses

How to unblock wgetch?


I have one school assignment in which I shall implement one game based on client-server architecture. The server side controls all of the game, and the client side has just an image of what is going on. One of the features of the server is to kick out clients from the game, and here comes the problem.

I have one thread on client to receive messages from the server and the main thread receives input from the user, but when the first thread receives shutdown comand, the main thread is waiting for one key from the client before executing the shutdown.

My question is : is there any way to unblock the wgetch on the main thread to make it not stay waiting for a key and execute the shutdown ?

Code :

    void *trata_fifo(void *dados) {

int i;

RESPONSE resp;
char namepipe[MAX];

sprintf(namepipe, CLIENT_FIFO, getpid());
mkfifo(namepipe, 0600);
fd_res = open(namepipe, O_RDWR);


do {
    i = read(fd_res, &resp, sizeof (RESPONSE));

        drawGame(resp);
        if (resp.command == 3) {
            wclear(info_win);
            box(info_win, 0, 0);
            wattron(info_win, A_REVERSE | A_BOLD);
            mvwprintw(info_win, 2, 4, "Score");
            mvwprintw(info_win, 4, 5, " %d ", resp.points);
            mvwprintw(info_win, 6, 2, "Bombinhas");
            mvwprintw(info_win, 8, 5, " %d ", resp.bombinha);
            mvwprintw(info_win, 10, 2, "Megabombas");
            mvwprintw(info_win, 12, 5, " %d ", resp.megaBomba);
            wrefresh(info_win);
        }

        if (resp.command == 4) {//here
            SHUTDOWN = true;
            write(STDIN_FILENO,NULL,0);//i tried this , but its not working
        }
        if (resp.command == 5) {
            SHUTDOWN = true;
        }
    }

} while (!SHUTDOWN);

close(fd_res);
pthread_exit(NULL);

    }


    int main() {

REQUEST client;
pthread_t tarefa;
int highlight = 1, choice = 0, opt;

int startx = 0, starty = 0;

signal(SIGINT, handleSignalCli);
signal(SIGUSR1, handleSignalCli);
signal(SIGALRM, handleSignalCli);



if (access(SERVER_FIFO, F_OK) != 0) //Verificar se servidor esta correndo
{
    perror("[ERROR] Server ins't running...!/n");
    exit(EXIT_FAILURE);
}

if (pthread_create(&tarefa, NULL, trata_fifo, NULL) != 0) {
    fprintf(stderr, "[ERROR] Creating Thread\n");
    exit(EXIT_FAILURE);
}

fd = open(SERVER_FIFO, O_WRONLY);
if (!fd) {
    perror("[ERROR] Opening Server Fifo...!\n");
    exit(EXIT_FAILURE);
}

    /*...*/
while (!SHUTDOWN) {
    cbreak();
    keypad(game_win, TRUE);
    noecho();
    client.command = 3;
    client.tecla = wgetch(game_win);
    res = write(fd, &client, sizeof (client));
}

close(fd);
pthread_join(tarefa, NULL);

delwin(game_win);
delwin(main_win);
endwin();

exit(0);

    }

PS:resp.comand = 4 means server is kicking out the player/client. Sorry for bad english :)


Solution

  • In curses, you have three choices

    • blocking reads with no time limit (which is what you're doing now)
    • blocking reads with a time limit, using wtimeout
    • non-blocking reads, using nodelay

    Both of those (wtimeout and nodelay) are set on the given window, and can be modified as needed. A wgetch on a different window is unaffected.

    For example, to use non-blocking reads for game_win, you could add this near the keypad call:

    nodelay(game_win, TRUE);