1

PRETEND THEY'RE NOT PARENT AND CHILD PROCESSES EVEN THOUGH THEY ARE.

MAKE FIFO:

/* Create response FIFO. */
if (mkfifo(RESP_FIFO_NAME, FIFO_MODE) == -1) {
    if (errno != EEXIST) {
        fprintf(stderr, "Server: Couldn’t create %s FIFO.\n", RESP_FIFO_NAME);
        exit(1);
    }
}

Fork:

/* 3. Fork the client process. */
switch (fork()) {

/* Fork failed. */
case (pid_t) -1:
    fprintf(stderr, "Call to fork failed.\n"); 
    exit(1);

/* Client (child) process. */
case 0:
    execlp(CLIENT_NAME, CLIENT_NAME, argv[SERVER_CMD_FILE_ARG], argv[SERVER_LOG_FILE_ARG], NULL);

/* Server (parent) Process */
default:
    sleep(1);
    server(infd, outfd, argv[INIT_DB_ARG], argv[FINAL_DB_ARG]);
} /* End of switch. */

server function:

int server(int infd, int outfd, char *init_db_name, char *final_db_name) {
...
if ((outfd = open(RESP_FIFO_NAME, O_WRONLY)) == -1) {
            fprintf(stderr, "Server: Failed to open %s FIFO.\n", RESP_FIFO_NAME);
            perror(RESP_FIFO_NAME);
            exit(1);
        }
...
}

client program:

printf("RESP_FIFO FILE DESCRIPTOR: %d\n", infd);
/* Open the response FIFO for reading. */
if ((infd = open(RESP_FIFO_NAME, O_RDONLY)) == -1) {
    fprintf(stderr, "Client: Failed to open %s FIFO.\n", RESP_FIFO_NAME);
    exit(1);
}
else printf("RESP_FIFO FILE DESCRIPTOR: %d\n", infd);

TL;DR The open for reading call in client program is not being executed before the open for writing call in the server program.

ICantNameMe
  • 93
  • 1
  • 1
  • 7
  • Try to use `strace` for debug with with arguments `open` called. Maybe you use `demonize()` that change current directory? – azat May 06 '13 at 10:56
  • Also pay attention to `chdir()` in strace output – azat May 06 '13 at 11:01
  • I don't have admin access or anything, I'm just using a TTY client. If the command is just `strace` I got an output of `ERROR: unable to open /dev/log`. – ICantNameMe May 06 '13 at 11:03
  • Could you compile on the local machine? Command is `strace /path/to/executable` – azat May 06 '13 at 11:08
  • Which OS do you have installed there? – azat May 06 '13 at 11:09
  • No, I'm running Windows using PuTTY to connect to a Unix server where my files are run and compiled. My program also takes in command line arguments, but I can't even run `strace` with my access so this doesn't really help me. – ICantNameMe May 06 '13 at 11:11
  • `uname -a` reports `5.10 Generic_142900-06 sun4u sparc SUNW,Sun-Fire-V440`, ie. Sun Sparc architecture, running bash. – ICantNameMe May 06 '13 at 11:13
  • You trying to run the wrong strace, can you run `truss`? (see man for needable options, or just google it). Also what about `chdir()/`daemonaze()`? – azat May 06 '13 at 11:16
  • Ran `truss -t'open' $(program_name)` and got `open("command.txt", O_RDONLY|O_NONBLOCK) = 5` `Response FIFO created.` `open("response.txt", O_WRONLY|O_NONBLOCK) Err#6 ENXIO` So I still know that my FIFO is not opening for reading for some reason. – ICantNameMe May 06 '13 at 11:39
  • `truss -t'chdir' $(program_name)` prints nothing extra for me. Literally it's just the program's output. Maybe I misinterpreted what you meant. http://stackoverflow.com/questions/16398377/debugging-open-command-call-with-truss – ICantNameMe May 06 '13 at 12:14
  • Could you make simple example that can reproduce the issue? – azat May 06 '13 at 12:40
  • Opening the pipe after fork is probably not the best idea (AFAIK). Child processes has the same file descriptors as parent (they are copied during the fork) - it does not work when you create a pipe in a child because parent does not know about it. If you need two-side communication for processes probably `zeromq` is nice and easy tool to do this (if you do not want to play with semaphores or fifos). – spinus May 06 '13 at 12:48
  • I'm pretending these aren't parent-child processes though. I'm using independent file descriptors between files with identical variable names. I suppose I didn't mention that, so I apologize. The reason I opened the FIFO after the pipe was because the program quits immediately if I try to open for writing before I can open for reading, which needs to be opened by the client/child process first. However, this still does not execute first, leading to my problem. – ICantNameMe May 06 '13 at 13:00

4 Answers4

1

Are you opening the response fifo for writing before its other end is open for reading? See fex. Having a trouble with opening FIFO in C

Either wait until you know the FIFO is open for reading or make the open blocking, to wait for the client. Also make sure the server has write permission for the FIFO file.

Community
  • 1
  • 1
thuovila
  • 1,960
  • 13
  • 21
  • I called the open commmand `outfd = open(CMD_FIFO_NAME, O_WRONLY | O_NONBLOCK)` and the file descriptor `outfd` changed values, but **this open call is not shown when I call truss**. – ICantNameMe May 06 '13 at 12:38
  • Could you add some code. Im wondering if you are creating the FIFO right. Are you calling mkfifo or mknod at some point? – thuovila May 06 '13 at 12:43
  • 1
    In `mkfifo()` you use `RESP_FIFO_NAME` but in the `open()` you use `respfifo`. Are you positive they contain the same filename? Maybe you could try to edit your fifo code down to a [http://www.sscce.org/](http://www.sscce.org/) and show it all to us. Perhaps it might also start working, when you redo it. – thuovila May 06 '13 at 12:56
  • Oh that code is old. `respfifo` is gone, all instances were directly replaced with `RESP_FIFO_NAME`. I didn't expect this thread to live this long, but I should probably replace my code then. – ICantNameMe May 06 '13 at 13:01
  • Where is RESP_FIFO_NAME defined? Does the execed client process see it? I.e have you checked that result.txt is created in the working directory? Also, I suggest defining the pipe with a full path name, e.g. "/tmp/result-pipe" – thuovila May 06 '13 at 13:16
  • it's a macro constant defined a string literal across both programs. `#define RESP_FIFO_NAME "response.txt"` I assumed it was completely arbitrary what the name was and I didn't bother making it inside a folder because 1. I'm still debugging so the program may not even finish execution anyway and 2. I may have to manually delete it since I don't have an unlink command set up yet. – ICantNameMe May 06 '13 at 13:21
  • Then the name is OK I think – thuovila May 06 '13 at 13:37
  • Well I think it's working now... the error was probably caused by me opening the FIFO for reading but not actually reading anything, but still writing something into it from the other end, hence why I was getting an error. Now that I just wasted 6 hours on a simple problem, I have a segfault to solve. – ICantNameMe May 06 '13 at 13:57
  • On solaris the debugger is (most often) called _dbx_ Running _dbx core.file_ and typing _where_ should get you pretty far along in solving the segfault. – thuovila May 06 '13 at 14:04
  • `dbx: File 'core' is not executable` – ICantNameMe May 06 '13 at 14:18
  • 1
    My bad, its _dbx executable-name core-file_. See [here](http://docs.oracle.com/cd/E19205-01/819-5257/blabq/index.html) for details. – thuovila May 06 '13 at 14:46
  • Well it managed to tell me the function name that was causing the segfault at least, but it doesn't completely work because my program requires command line arguments and dbx completely ignores them when called. It gave me an address location too (i believe, it's some kind of pointer), but it couldn't give me a line number. – ICantNameMe May 06 '13 at 14:49
  • These comments are getting a bit out of hand, but you can pass the dbx debugger program arguments by using the -r switch. See [here](http://docs.oracle.com/cd/E19205-01/819-5257/blawp/index.html). There are also other ways. You can find good dbx guides with google/duckduckgo – thuovila May 06 '13 at 19:51
0

What about pipe() for this

From pipe(2):

Create descriptor pair for interprocess communication.

The pipe() function creates a pipe (an object that allows unidirectional data flow) and allocates a pair of file descriptors. The first descrip- tor connects to the read end of the pipe; the second connects to the write end.

Data written to fildes1 appears on (i.e., can be read from) fildes[0].

You can look how memcached use it

azat
  • 3,545
  • 1
  • 28
  • 30
  • I need to use FIFO's for this project in order to teach me how two unrelated processes can communicate. pipes can be used for processes in a parent-child relationship only, I believe. – ICantNameMe May 06 '13 at 11:16
0

Yes, without a reader, an open() of a filesystem FIFO for writing will either block or, in the nonblocking case, fail with ENXIO.

You have at least two easy options.

First, you could open the "command" FIFO, nonblocking, for reading in addition to writing, either O_RDWR or with two separate file descriptors, one O_RDONLY and one O_WRONLY.

Second, you could use a filesystem socket instead, and have the server listen there. That gives you a bi-directional communication channel over one ofile.

UNIX gives you other options, too — message queues or files or shared memory segments, perhaps using signals for one interlocutor to prod the other, come to mind — but the above are quite straightforward.

pilcrow
  • 56,591
  • 13
  • 94
  • 135
  • I think the explicit assignment was to use FIFOs, if understood the question correctly. It has been revised several times. – thuovila May 06 '13 at 13:11
  • "First, you could open the "command" FIFO for reading in addition to writing, either O_RDWR or with two separate file descriptors, one O_RDONLY and one O_WRONLY." I am using FIFOs with O_RDONLY and O_WRONLY. The problem is if i don't use O_NONBLOCK my program just sleeps waiting for the other process... – ICantNameMe May 06 '13 at 13:18
  • Thats called a deadlock. You have to interleave the opens in the server and client so that neither side gets blocked (forever). pilcrows first suggestion is good (and also what I suggested:). If the correctly sequenced opens on the pipes still block, there is some other error (eg wrong pipe name or similar). – thuovila May 06 '13 at 13:19
0

I wrote into a FIFO on one end without reading out of the other end. Just having the files open for reading and writing is not enough, you have to actually read the text out of the FIFO or the program will incur an error (ENXIO if you have O_NONBLOCK flag set).

ICantNameMe
  • 93
  • 1
  • 1
  • 7