Swarm-NG  1.1
memorymap.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * Copyright (C) 2005 by Mario Juric *
3  * mjuric@astro.Princeton.EDU *
4  * *
5  * This program is free software; you can redistribute it and/or modify *
6  * it under the terms of the GNU General Public License as published by *
7  * the Free Software Foundation; either version 2 of the License, or *
8  * (at your option) any later version. *
9  * *
10  * This program is distributed in the hope that it will be useful, *
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of *
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
13  * GNU General Public License for more details. *
14  * *
15  * You should have received a copy of the GNU General Public License *
16  * along with this program; if not, write to the *
17  * Free Software Foundation, Inc., *
18  * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
19  ***************************************************************************/
20 
26 #include "memorymap.hpp"
27 #include "util.hpp"
28 
29 #include <sys/types.h>
30 #include <sys/stat.h>
31 #include <fcntl.h>
32 #include <string.h>
33 #include <errno.h>
34 #include <unistd.h>
35 
36 #include <iostream>
37 #include <cassert>
38 
39 #define ERROR(msg) throw MemoryMapError(msg)
40 
41 
42 
43 using namespace std;
44 
45 const int MemoryMap::pagesize = getpagesize();
46 
47 void MemoryMap::pagesizealign(ostream &out)
48 {
49  size_t at = out.tellp();
50  size_t offs = at % pagesize;
51  if(offs) { out.seekp(pagesize - offs, ios::cur); }
52 }
53 
54 void MemoryMap::pagesizealign(istream &in)
55 {
56  size_t at = in.tellg();
57  size_t offs = at % pagesize;
58  if(offs) { in.seekg(pagesize - offs, ios::cur); }
59 }
60 
61 void MemoryMap::open(const std::string &fn, size_t length_, size_t offset, int mode, int mapstyle)
62 {
63  if(offset > 0 && (offset % pagesize)) { ERROR("Invalid offset requested for memory mapped area - not a multiple of pagesize (" + str(pagesize) + ")"); }
64 
65  int flags = 0;
66 
67  if(mode & rw) { flags |= O_RDWR | O_CREAT; }
68  else if(mode & ro) { flags |= O_RDONLY; }
69  else if(mode & wo) { flags |= O_WRONLY | O_CREAT; }
70  else ERROR("Invalid mode parameter - mode needs to include ro, wo or rw");
71 
72  int create_mode = 00600;
73 
74  int fd = ::open(fn.c_str(), flags, create_mode);
75 
76  if(fd == -1)
77  {
78  fd = 0;
79  ERROR(string("Error opening file [") + fn + "]");
80  }
81 
82  if(length_ == 0 && !(flags & O_WRONLY))
83  {
84  struct stat buf;
85  fstat(fd, &buf);
86  length_ = buf.st_size;
87  }
88 
89  close();
90  filename = fn;
91  open(fd, length_, offset, mode, mapstyle, true);
92 }
93 
94 void MemoryMap::open(int fd_, size_t length_, size_t offset, int prot, int mapstyle, bool closefd_)
95 {
96  close();
97  length = length_;
98  closefd = closefd_;
99  fd = fd_;
100 
101  // check if the length of the file is sufficient to hold the requested length
102  // if not, enlarge if possible
103  struct stat buf;
104  fstat(fd, &buf);
105  if(buf.st_size < offset + length)
106  {
107  if(!(prot & PROT_WRITE))
108  {
109  close();
110  ERROR(string("A read-only file is smaller than the length requested to be memory mapped"));
111  }
112 
113  // resize the file
114  lseek(fd, offset + length - 1, SEEK_SET);
115  char b = 1;
116  write(fd, &b, 1);
117  }
118 
119  map = mmap(0, length, prot, mapstyle, fd, offset);
120  if(map == MAP_FAILED)
121  {
122  map = NULL;
123  close();
124  ERROR(string("mmap failed:") + strerror(errno) + " {filename:" + filename + ",length:" + str(length) + ", offset:" + str(offset)+ "}");
125  }
126 }
127 
128 void MemoryMap::sync()
129 {
130  assert(fd != 0);
131  assert(map != NULL);
132  msync(map, length, MS_SYNC);
133 }
134 
135 MemoryMap::MemoryMap()
136 : filename(""), fd(0), map(NULL), length(0), closefd(true)
137 {
138 }
139 
140 MemoryMap::MemoryMap(const std::string &fn, size_t length_, size_t offset, int mode, int mapstyle)
141 : filename(fn), fd(0), map(NULL), length(length_)
142 {
143  open(fn, length, offset, mode, mapstyle);
144 }
145 
146 void MemoryMap::close()
147 {
148  if(map != NULL)
149  {
150  if(munmap(map, length) == -1) { ERROR(string("Error unmapping file [") + filename + "]"); }
151  map = NULL;
152  }
153 
154  if(closefd && fd != 0)
155  {
156  if(::close(fd) == -1) { ERROR(string("Error closing file [") + filename + "]"); }
157  fd = 0;
158  }
159 }
160 
162 {
163  close();
164 }