/* @(#)osm.c 17.1.1.1 (ES0-DMD) 01/25/02 17:35:08 */ /*=========================================================================== Copyright (C) 1995 European Southern Observatory (ESO) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 675 Massachusetss Ave, Cambridge, MA 02139, USA. Corresponding concerning ESO-MIDAS should be addressed as follows: Internet e-mail: midas@eso.org Postal address: European Southern Observatory Data Management Division Karl-Schwarzschild-Strasse 2 D 85748 Garching bei Muenchen GERMANY ===========================================================================*/ /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .TYPE Module .NAME osm .LANGUAGE C .AUTHOR IPG-ESO Garching .CATEGORY Host operating system interfaces. Memory mapping. .COMMENTS Virtual memory mapping and memory handling routines. The routines include i/o using mapping services as well as virtual memory allocation and control. The routines return always a non-negative integer number on successful return. Otherwise, a value of -1 is set to indicate an error condition and the variable ``oserror'' contains the symbolic error code. .VERSION [0.0] 25-Aug-1986 Definition .VERSION [1.0] 02-Dec-1986 Programmation .VERSION [1.5] 01-Jul-1987 Allow shared memory to be used in the file mapping. .VERSION [1.6] 26-May-1988 Cosmetic changes. CG .VERSION [1.7] 19-Dec-1990 Not checking FNAME_LEN any more CG. .VERSION [2.0] 19-Feb-1992 filestatus structure now on osfile.h CG. .VERSION [2.1] 17-Jul-1992 Shared memory is now dropped. CG. .VERSION [3.1] 21-Apr-1993 Posix compliant CG. ------------------------------------------------------------*/ /* * Define _POSIX_SOURCE to indicate * that this is a POSIX program */ #define _POSIX_SOURCE 1 #include /* ANSI-C prototyping */ #include #include #include #include #include #include #include #ifdef FASTMEM_SET #include #endif #ifdef OSERROR_D /* oserror already defined (Silicon G)*/ #define oserror midaserror #endif extern int oserror; #define _NFILE_ 64 #define _NMAPPED 256 struct map_zone { char *maddr; /* pointer to the beginning of the memory array where */ /* the mapped file segment is stored. */ off_t faddr; /* address in the file of the segment to map */ size_t size; /* length of the mapped segment */ short flush; /* switch set to indicate that the segment has to be */ /* flushed on disk on close or on unmap operation */ }; struct file_map { char *fname; /* pointer to the file name (used in osmclose) */ short nmap; /* number of mapped segments for this file */ short mode; /* file open mode. To be used to control the access on */ /* file in read and write. */ struct map_zone mapped[_NMAPPED]; /* sub-structure to describe each mapped segment */ /* with the information necessary to handle it. */ /* _NMAPPED is the maximum number of mapped segment */ /* for one file. It is defined in */ }; static struct file_map fmap[_NFILE_]; /* a maximum of _NFILE_ are forecast to be */ /* opened at the same time, so one */ /* occurrence of the above structure is */ /* necessary to describe all the files */ /* simultaneously opened by the process. */ int osmopen(phname, mode) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Opens an EXISTING data file. The filename supplied by the calling program is in host dependent form. Access to the file is via the mapping system services (which do not exist under Unix !!). (For the Unix version, an emulation of a mapping system service is done.) The variable mode take the following value : READ, WRITE or READ_WRITE. In any case, the file is supposed to exist. .RETURNS Upon successful completion a positive number with the .RETURNS file descriptor is returned. .REMARKS System dependencies: -- UNIX: osfinfo(0), open(2) ------------------------------------------------------------*/ char *phname; /* IN : physical filename */ int mode; /* IN : open mode */ { struct filestatus fs; /* structure describing files. Usefull */ /* here to get the file size */ int fid; /* file identification */ /* /////////////////////////////////////////////////////////////////////// // PSEUDO_CODE // ----------- // in case of read_only open mode : // check if file exists, // if file can be opened, // then set file descriptor structure (fname, open_mode, number of // mapped zones) // else set the return code (file id) to -1 and oserror to the // error code. // in case of write only open mode // then set file descriptor structure ... // else set the return code (file id) to -1 and oserror to the // error code. // in case of read write : // same as for read /////////////////////////////////////////////////////////////////////////// */ switch (mode) { case READ: /* case of read_only file */ /* * 1. check for file existance */ if (osfinfo(phname, &fs) == 0) { /* * 2. open file */ if ((fid = open(phname, O_RDONLY)) != -1) { if (fid >= _NFILE_) { oserror = EINVAL; fid = -2; /* indicate overflow */ break; } fmap[fid].fname = &(*phname); /* update fmap */ fmap[fid].nmap = 0; fmap[fid].mode = READ; } } else fid = -1; break; case WRITE: /* case of write only file. */ if (osfinfo(phname, &fs) == 0) { /* * prepare information to handle it */ if ((fid = open(phname, O_RDWR)) != -1) { if (fid >= _NFILE_) { oserror = EINVAL; fid = -2; /* indicate overflow */ break; } fmap[fid].fname = &(*phname) ; fmap[fid].nmap = 0; fmap[fid].mode = WRITE; } } else fid = -1; break; case READ_WRITE: /* case of read_write */ /* * 1. check for existance */ if (osfinfo(phname, &fs) == 0) { /* * 2. open file in read_write mode */ if ((fid = open(phname, O_RDWR)) != -1) { if (fid >= _NFILE_) { fid = -2; /* indicate overflow */ break; } fmap[fid].fname = &(*phname); fmap[fid].nmap = 0; fmap[fid].mode = READ_WRITE; } } else fid = -1; break; default: oserror = 0; fid = -1; break; } return (fid); } int osmclose(fid) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Closes data file. Access to the file is done by the file identification as returned by the routine osmopen. .RETURNS Value 0 on normal return. .REMARKS System dependencies: -- UNIX: write(2), close(2), free() ------------------------------------------------------------*/ int fid; /* IN : file identifier */ { int ret, i; /* ////////////////////////////////////////////////////////////////////////// // PSEUDO_CODE // ----------- // for all opened segment // check if file must be flushed // check if write can be done successfully (sequential write) // then free the memory // else break // end for // if return code is correct // then check if close can be done successfully // else set return code to -1 // endif ///////////////////////////////////////////////////////////////////////// */ /* 1. check if segments have to be flushed on disk before to close */ ret = 0; for (i=0;i only allocate mem */ { /* but also set segment information */ ret = nobyt; cur_map = fmap[fid].nmap; fmap[fid].mapped[cur_map].maddr = *pbuf; fmap[fid].mapped[cur_map].faddr = address; fmap[fid].mapped[cur_map].size = ret; fmap[fid].mapped[cur_map].flush = 1; fmap[fid].nmap++; } } else { /* memory could not be allocated */ oserror = ENOMEM; ret = 0; } return(ret); } int osmunmap(fid, address) /*++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ .PURPOSE Puts back on disk (if modified) the segment specified by the file id and the address that has previously been mapped by osmmap. .RETURNS 0 on normal completion, -1 on error. .REMARKS System dependencies: -- UNIX: lseek(2), write(2), free() -- MIDAS VMS Equivalence: ------------------------------------------------------------*/ int fid; /* IN : file identifier */ char *address; /* IN : address of the segment in the memory */ /* ///////////////////////////////////////////////////////////////////////// // PSEUDO_CODE // ----------- // search for the given address in the structure // if found // then if segment to be flushed on disk // then set file pointer to the right place in file // write back the whole segment on disk // free the memory // set flush switch to zero // else do nothing // else return an error code : the address is wrong and does not // correspond to an actual segement in the // memory. // endif // ////////////////////////////////////////////////////////////////////////// */ { register i; int ret=0; for (i=0;fmap[fid].mapped[i].maddr !=address && i < fmap[fid].nmap;i++); if (fmap[fid].mapped[i].maddr == address) { /* unmap only if to be flushed */ if (fmap[fid].mapped[i].flush) { if (lseek(fid,fmap[fid].mapped[i].faddr, FILE_START) != -1) { ret = (int) write(fid, address, fmap[fid].mapped[i].size); if (ret != fmap[fid].mapped[i].size) { oserror = errno; ret = -1; } else { /* write succeeded */ free(fmap[fid].mapped[i].maddr); fmap[fid].mapped[i].flush = 0; ret = 0; } } else { /* seek failed */ oserror = errno; ret = -1; } } else ret = 0; /* no flush needed */ } else { ret = -1; oserror = EINVAL; } return(ret); }