From 9d70096709e7f9d63787a45d5f5ac626b5fb0933 Mon Sep 17 00:00:00 2001 From: tradke Date: Sun, 16 Oct 2005 10:12:13 +0000 Subject: For announced JPEGs: write to a temporary file first and then (atomically) rename it to the real output file. This fixes problems with a threaded HTTPD where JPEG files could be downloaded while they were still being written to. git-svn-id: http://svn.cactuscode.org/arrangements/CactusIO/IOJpeg/trunk@116 eff87b29-5268-4891-90a3-a07138403961 --- src/Write.c | 58 ++++++++++++++++++++++++++++++++++++++++------------------ 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/src/Write.c b/src/Write.c index 4005fd9..faf87ef 100644 --- a/src/Write.c +++ b/src/Write.c @@ -313,7 +313,7 @@ static void WriteData (const cGH *GH, int vindex, const char *alias, int dim, unsigned char *dataout; const ioJpegGH *myGH; ioAdvertisedFileDesc advertised_file; - char *filename, *fullname; + char *filename, *tmpfilename, *fullname; char slicename[30]; const char *extensions[] = {"xy", "xz", "yz"}; DECLARE_CCTK_PARAMETERS @@ -338,50 +338,72 @@ static void WriteData (const cGH *GH, int vindex, const char *alias, int dim, sprintf (slicename, "%s_[%d]", extensions[dir], myGH->sp2xyz[dim-1][dir]); } - filename = (char *) malloc (strlen (myGH->out_dir) + strlen (alias) + - sizeof (slicename) + 20); + filename = malloc (strlen (myGH->out_dir) + strlen (alias) + + sizeof (slicename) + 20); if (CCTK_Equals (mode, "remove")) { sprintf (filename, "%s%s_%s.jpeg", myGH->out_dir, alias, slicename); + tmpfilename = malloc (strlen (filename) + 5); + sprintf (tmpfilename, "%s.tmp", filename); } else { sprintf (filename, "%s%s_%s.it_%d.jpeg", myGH->out_dir, alias, slicename, GH->cctk_iteration); + tmpfilename = NULL; } - file = fopen (filename, "w"); + /* Write a JPEG file to be advertised to a temporary file first + and rename it later. + This fixes a racing problem with HTTPD when running with pthreads support: + a file could be downloaded (through the HTTPD thread) while is was still + being written to (in the main simulation thread). + Now the JPEG is written to a temporary file first and then (atomically) + renamed. */ + file = fopen (tmpfilename ? tmpfilename : filename, "w"); if (file) { /* write the data */ WriteJPEGToFileRGB (hsize[0], hsize[1], dataout, colormap_quality, file); - /* advertise the file for downloading */ - if (CCTK_Equals (mode, "remove") && myGH->out_last[vindex] < 0) + /* close the file */ + fclose (file); + + /* in "remove" mode: rename and advertise the file for downloading */ + if (tmpfilename) { - fullname = CCTK_FullName (vindex); - advertised_file.slice = slicename; - advertised_file.thorn = CCTK_THORNSTRING; - advertised_file.varname = fullname; - advertised_file.description = "Jpegs of slices"; - advertised_file.mimetype = "image/jpeg"; + if (rename (tmpfilename, filename)) + { + CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, + "Cannot rename temporary output file '%s' into '%s'", + tmpfilename, filename); + } + else if (myGH->out_last[vindex] < 0) + { + fullname = CCTK_FullName (vindex); + advertised_file.slice = slicename; + advertised_file.thorn = CCTK_THORNSTRING; + advertised_file.varname = fullname; + advertised_file.description = "Jpegs of slices"; + advertised_file.mimetype = "image/jpeg"; - IOUtil_AdvertiseFile (GH, filename, &advertised_file); + IOUtil_AdvertiseFile (GH, filename, &advertised_file); - free (fullname); + free (fullname); + } } - - /* close the file */ - fclose (file); } else { CCTK_VWarn (1, __LINE__, __FILE__, CCTK_THORNSTRING, - "Cannot open IOJpeg output file '%s'", filename); + "Cannot open IOJpeg %s output file '%s'", + tmpfilename ? "temporary" : "", + tmpfilename ? tmpfilename : filename); } /* clean up */ free (dataout); + free (tmpfilename); free (filename); } -- cgit v1.2.3