I have a C program like so (copied from here):
#include <fcntl.h>
#define PATH "testpipe"
#define MESSAGE "We are not alone"
int main()
{
int fd;
mkfifo ( PATH, 0666 );
fd = open ( PATH, O_WRONLY );
write ( fd, MESSAGE, sizeof ( MESSAGE ) );
close ( fd );
unlink ( PATH );
return 0;
}
and a shell script like so:
echo < testpipe
Once I execute the C program, the echo statement returns, but We are not alone
is not printed. I have also tried creating the pipe from the command line, and with mknod
instead, and it makes no difference. Why is this not working?
EDIT:
A lot of people have pointed out that the problem is with echo
and not with C
, problem is, I need it to work with something like echo
(omxplayer
actually, as I am issuing video control commands to it, ie. p
for pause or q
for quit). Therefore, I would appreciate some answers indicating how to change the C code to make it work with the echo
statement, as opposed to vice versa
EDIT:
I didn't include the full code as it uses omxplayer
and is rather large, but some users requested it, therefore, here is as minimal as I could keep this MWE:
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#define PIPEPATH "testpipe"
#define VIDEOPATH "Matrix.mkv"
#define MESSAGE "q"
#define VIDEOPLAYER "omxplayer"
int main()
{
int fd;
pid_t pid;
pid_t wpid;
int status;
char shellCmd [ 1000 ];
struct timespec time1, time2; //used for sleeping
//Make pipe BEFORE forking
mkfifo ( PIPEPATH, 0666 );
if ( ( pid = fork () ) < 0 )
{
perror ( "Fork Failed\n" );
return -1;
}
else if ( pid == 0 )
{ //first child keeps pipe open
sprintf ( shellCmd, "tail -f /dev/null > %s", PIPEPATH );
if ( system ( shellCmd ) == -1 )
{
printf ( "Error: %s\n", shellCmd );
fflush(stdout);
}
}
else{
time1.tv_sec = 1L; //sleep for 1 second to let first child issue its command
time1.tv_nsec = 0L; //Dont worry about milli seconds
nanosleep ( &time1, &time2 );
if ( ( pid = fork () ) < 0 )
{
perror ( "Fork Failed\n" );
return -1;
}
else if ( pid == 0 )
{ //second child launches the movie
sprintf ( shellCmd, "cat %s | %s %s 2>&1 > /dev/null", PIPEPATH, VIDEOPLAYER, VIDEOPATH );
if ( system ( shellCmd ) == -1 )
{
printf ( "Error: %s\n", shellCmd );
fflush(stdout);
}
}
else
{
if ( ( pid = fork () ) < 0 )
{
perror ( "Fork Failed\n" );
return -1;
}
else if ( pid == 0 )
{ //third child waits 5 seconds then quits movie
time1.tv_sec = 5L; //sleep for 5 seconds
time1.tv_nsec = 0L; //Dont worry about milli seconds
nanosleep ( &time1, &time2 );
printf ( "Sleep over, quiting movie\n");
fflush(stdout);
fd = open ( PIPEPATH, O_WRONLY );
write ( fd, MESSAGE, sizeof ( MESSAGE ) );
close ( fd );
}
}
}
//Note the first child will never exit as it is a blocking shell script
while ( ( wpid = wait ( &status ) ) > 0 )
{
printf ( "Exit status of %d was %d (%s)\n", ( int ) wpid, status, ( status == 0 ) ? "accept" : "reject" );
fflush(stdout);
}
unlink ( PIPEPATH );
return 0;
As I pointed out, the program will never exit, so just issue a Ctrl+C }
Edit 3:
Ok I am making progress, it seems that what you give to the pipe and what you get back are not the same thing, run this script and observe:
#include <stdio.h>
#include <fcntl.h>
#define PIPE_PATH "testpipe"
int main( int argc, char *argv[] ) {
int fd;
FILE *fp;
char c;
if ( atoi ( argv [ 1 ] ) == 1 )
{
printf ("Writer [%s]\n", argv[1]);
mkfifo ( PIPE_PATH, 0666 );
fd = open ( PIPE_PATH, O_WRONLY );
c = getchar();
write(fd, c, 1);
close(fd);
}
else if ( atoi ( argv [ 1 ] ) == 2 )
{
printf ( "Reader [%s]\n", argv[1] );
fp = fopen( PIPE_PATH, "r" );
c = getc ( fp );
putchar ( c );
printf ( "\n" );
fclose ( fp );
unlink( PIPE_PATH );
}
return 0;
}
EDIT 4:
J.F. Sebastian asked some good questions, this is in response to those questions. What I am ultimately trying to do is to synchronize 2 or more instances of omxplayer playing the same movie on 2 or more raspberry pis. omxplayer-sync tries to achieve this, but it is not accurate, it is written in Python which is not suitable for this, and its approach is, IMO, not a good one. I am working my way up the food chain trying out the easiest solutions to see if they are viable. From easiest to hardest, here is what I have tried so far (or plan on trying)
- Launch
omxplayer
instances from the shell at an agreed upon time in future at the same time: FAIL - Launch
omxplayer
instances from a Python script (more accurate time wise) at an agreed upon time in future at the same time: FAIL - Launch
omxplayer
instances from a C program (even more accurate time wise) at an agreed upon time in future at the same time: FAIL - Launch and immediately pause, then unpause
omxplayer
instances from a Python script (more accurate time wise) at an agreed upon time in future at the same time: FAIL - Launch and immediately pause, then unpause (via
echo -n p > namedpipe
)omxplayer
instances from a C program (more accurate time wise) at an agreed upon time in future at the same time: FAIL - Launch and immediately pause, then unpause (via
write ( fd_of_named_pipe, 'p', sizeof ( 'p') );
)omxplayer
instances from a C program (more accurate time wise) at an agreed upon time in future at the same time: PENDING - Reimplement
omxplayer
and modulate play speeds to catch up with fastest player: FUTURE
Basically before investing a huge chunk of my life into understanding and then modifying the source code of omxplayer
(7) I want to see if using C's native write ( fd_of_named_pipe, 'p', sizeof ( 'p') )
operation is faster than its system(echo -n p > namedpipe)
call which forks a child and calls the shell to write to the named pipe (my hunch tells me it will be much faster, and hopefully more accurate). If this works and unpauses all instances to within 15ms, fantastic, I won't have to look at omxpleyer
's source code ever. If not, as a last resort I will start modifying the source code.