home *** CD-ROM | disk | FTP | other *** search
- Path: sparky!uunet!ukma!usenet.ins.cwru.edu!agate!ucbvax!lrw.com!leichter
- From: leichter@lrw.com (Jerry Leichter)
- Newsgroups: comp.os.vms
- Subject: re: Flushing file buffers to disk in VAX C
- Message-ID: <9301231826.AA03802@uu3.psi.com>
- Date: 23 Jan 93 17:15:07 GMT
- Sender: daemon@ucbvax.BERKELEY.EDU
- Distribution: world
- Organization: The Internet
- Lines: 131
-
-
- The problem:
- ------------
- I am running VMS 5.5-1 on a VAXstation 4000 model 60. I find that the
- C library call fsync() does not write the file buffers to disk as it
- is supposed to. Could someone else run the program below on this or
- earlier versions of VMS and check it? Run the program on one
- terminal, and when it stops to wait for input, kill the process using
- the STOP command from another terminal. If I understand the
- functionality of fsync() correctly, the buffers should have been
- flushed to disk - but when you look at the file after stopping the
- process, it is still empty. Is this a bug?
-
- Well, no. Since fsync() is neither documented nor supported, it can't
- possibly have any bugs; if its effect were to delete every other file in
- your directory, that might be rather undesireable behavior, but it wouldn't
- really be a BUG. :-)
-
- Some more details:
- -----------------
-
- I am using VAX C version 3.2 - earlier versions of the RTL may not
- support the fsync() call. It is not documented in the RTL reference
- manual even in the current version,
-
- As you see.... Could it be that perhaps you've found a REASON why it isn't
- documented or supported?
-
- but it is available in the
- library. There is no other way to ensure that C file data has been
- written to disk and the disk version is up-to-date (short of closing
- the file).
-
- I do not think the bug is in the fsync() routine itself; you can
- verify that the routine calls the RMS routine sys$flush() internally,
- as you might expect. (You can check this out by stepping through the
- assembly instructions with the debugger). I have tried calling
- sys$flush() directly, and it returns without error - still without
- writing the buffers to the file. So is the error in RMS?
-
- No. There's no error; you're just seeing an unexpected side effect of the
- implementation.
-
- In Unix, write() is a system call, and the standard I/O library is layered on
- top of it (and a few other system calls). VMS has not write() call; like all
- the other Unix calls, it is emulated by the VAX C RTL. However, for various
- reasons the emulation does NOT follow the design used in Unix: The standard
- I/O library is NOT implemented on top of the emulated write(). Instead, some
- common code ultimately underlies both.
-
- When you do a write() with the VAX C RTL, the data goes into a buffer managed
- by the RTL. Later, the RTL will pass the data off to RMS - but not right
- away. As a result, when you do a SYS$FLUSH, either through fsync() or by
- a direct call, RMS happily confirms that it has written out all the 0 bytes
- it has been handed so far.
-
- Even on Unix, if you want fsync() to work for a file opened through the stan-
- dard I/O library, you have to use fflush() first to get the data out of the
- stdio buffers and into the Unix system buffers, and only then do an fsync() to
- force the data to the disk. With the current VAX C RTL implementation, you
- have to do the same thing - but you also have to do it for data written with
- a write() call.
-
- Unfortunately, however, there does not exist a call to flush a file described
- by number, as opposed to one described by a FILE * - such a call would make no
- sense on Unix. There is a work-around, though: By using fdopen(), you can
- create a FILE * that points to a file opened using the "lower level" Unix I/O
- functions, then use fflush() on that. The resulting code - I've included a
- modified version of the posted source below - works as you wanted. (It should
- also work on Unix, where the fflush() will always be a no-op.)
-
- Another puzzle which I wonder if someone could explain to me - the C
- write() routine does not call RMS sys$write() at all. It calls
- sys$read() instead! Is there something wrong with my debugger symbols
- or is this the right thing for write() to do? It works, i.e. the file
- does get written to normally. Does this have something to do with the
- above problem?
-
- No. I suspect you are misinterpreting some Debugger display, but without all
- the details I can't be sure. (It's probably not worth it to try and resolve
- this.)
- -- Jerry
-
- ---------------- Modified source code begins here ---------------------------
- #include <stdio.h>
- #include <file.h>
-
- main()
- {
- int fd;
- FILE *fdf; /* Dummy FILE * for fd */
- char buf[] = "This is a test record\n";
- char testFileName[] = "chks.out";
-
- if ( (fd = open(testFileName, O_RDWR | O_CREAT)) < 0) {
- fprintf(stderr, "Error opening file. Exiting... \n");
- exit(0);
- }
-
- /*
- * Associate a FILE * with fd.
- */
- if ((fdf = fdopen(fd,"r+")) == NULL) {
- fprintf(stderr, "Error making FILE pointer. Exiting... \n");
- exit(0);
- }
-
- fprintf(stderr, "The file being used is %s\n\n", testFileName);
- fprintf(stderr, "%s%s%s%s%s",
- "A record has been written to the file and sync'ed. If the fsync()\n",
- "call works correctly the data should be in the file even if the\n",
- "process is stopped. You can now halt the process from another\n",
- "terminal or window using the STOP command, or hit any key to let\n",
- "it run to completion...\n"
- );
- fflush(stderr);
-
- write(fd, buf, sizeof(buf));
- fflush(fdf); /* Get the record to RMS */
- fsync(fd); /* Get it to the disk */
-
- /**
- You can now stop the process from another terminal or
- window while it waits, or let it complete.
- **/
- getchar();
-
- close(fd);
- fprintf(stderr, "Wrote the record and closed the file\n");
- }
-
-