Panda3D
|
00001 // Filename: subprocessWindowBuffer.cxx 00002 // Created by: drose (11Jul09) 00003 // 00004 //////////////////////////////////////////////////////////////////// 00005 // 00006 // PANDA 3D SOFTWARE 00007 // Copyright (c) Carnegie Mellon University. All rights reserved. 00008 // 00009 // All use of this software is subject to the terms of the revised BSD 00010 // license. You should have received a copy of this license along 00011 // with this source code in a file named "LICENSE." 00012 // 00013 //////////////////////////////////////////////////////////////////// 00014 00015 #include "subprocessWindowBuffer.h" 00016 #include <sys/mman.h> 00017 #include <fcntl.h> 00018 #include <string.h> 00019 00020 #include <iostream> 00021 using namespace std; 00022 00023 const char SubprocessWindowBuffer:: 00024 _magic_number[SubprocessWindowBuffer::magic_number_length] = "pNdaSWB"; 00025 00026 //////////////////////////////////////////////////////////////////// 00027 // Function: SubprocessWindowBuffer::operator new 00028 // Access: Private 00029 // Description: Placement operator. Returns addr, a trivial 00030 // pass-through. 00031 //////////////////////////////////////////////////////////////////// 00032 void *SubprocessWindowBuffer:: 00033 operator new(size_t, void *addr) { 00034 return addr; 00035 } 00036 00037 //////////////////////////////////////////////////////////////////// 00038 // Function: SubprocessWindowBuffer::Constructor 00039 // Access: Private 00040 // Description: This constructor is private; it is not intended to be 00041 // called directly. It is used in make_buffer() to 00042 // create a temporary local object, to determine the 00043 // required mmap_size for a given window size. 00044 //////////////////////////////////////////////////////////////////// 00045 SubprocessWindowBuffer:: 00046 SubprocessWindowBuffer(int x_size, int y_size) { 00047 memcpy(_this_magic, _magic_number, magic_number_length); 00048 _x_size = x_size; 00049 _y_size = y_size; 00050 _row_size = _x_size * 4; 00051 _framebuffer_size = _row_size * y_size; 00052 _event_in = 0; 00053 _event_out = 0; 00054 _last_written = 0; 00055 _last_read = 0; 00056 00057 _mmap_size = sizeof(*this) + _framebuffer_size; 00058 } 00059 00060 //////////////////////////////////////////////////////////////////// 00061 // Function: SubprocessWindowBuffer::Copy Constructor 00062 // Access: Private 00063 // Description: 00064 //////////////////////////////////////////////////////////////////// 00065 SubprocessWindowBuffer:: 00066 SubprocessWindowBuffer(const SubprocessWindowBuffer ©) : 00067 _mmap_size(copy._mmap_size), 00068 _x_size(copy._x_size), 00069 _y_size(copy._y_size), 00070 _row_size(copy._row_size), 00071 _framebuffer_size(copy._framebuffer_size) 00072 { 00073 memcpy(_this_magic, _magic_number, magic_number_length); 00074 _event_in = 0; 00075 _event_out = 0; 00076 _last_written = 0; 00077 _last_read = 0; 00078 } 00079 00080 //////////////////////////////////////////////////////////////////// 00081 // Function: SubprocessWindowBuffer::Destructor 00082 // Access: Private 00083 // Description: 00084 //////////////////////////////////////////////////////////////////// 00085 SubprocessWindowBuffer:: 00086 ~SubprocessWindowBuffer() { 00087 } 00088 00089 //////////////////////////////////////////////////////////////////// 00090 // Function: SubprocessWindowBuffer::new_buffer 00091 // Access: Public, Static 00092 // Description: Call this method to create a new buffer in shared 00093 // memory space. Supply the desired size of the window. 00094 // 00095 // This method will create the required shared-memory 00096 // buffer and return a SubprocessWindowBuffer allocated 00097 // within that shared memory, or NULL if there is a 00098 // failure allocating sufficient shared memory. 00099 // 00100 // It also creates a temporary file on disk and returns 00101 // fd, mmap_size, and filename, which the caller must 00102 // retain and eventually pass to destroy_buffer(). The 00103 // filename should be passed to the child process to 00104 // open with open_buffer(). 00105 //////////////////////////////////////////////////////////////////// 00106 SubprocessWindowBuffer *SubprocessWindowBuffer:: 00107 new_buffer(int &fd, size_t &mmap_size, string &filename, 00108 int x_size, int y_size) { 00109 mmap_size = 0; 00110 fd = -1; 00111 00112 filename = tmpnam(NULL); 00113 00114 fd = open(filename.c_str(), O_RDWR | O_CREAT | O_EXCL, 0600); 00115 if (fd == -1) { 00116 perror(filename.c_str()); 00117 return NULL; 00118 } 00119 00120 // Create a temporary object to determine the required size. 00121 SubprocessWindowBuffer temp(x_size, y_size); 00122 mmap_size = temp._mmap_size; 00123 00124 // Ensure the disk file is large enough. 00125 size_t zero_size = 1024; 00126 char zero[zero_size]; 00127 memset(zero, 0, zero_size); 00128 for (size_t bi = 0; bi < mmap_size; bi += zero_size) { 00129 write(fd, zero, zero_size); 00130 } 00131 00132 void *shared_mem = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, 00133 MAP_SHARED, fd, 0); 00134 if (shared_mem == (void *)-1) { 00135 // Failure to map. 00136 close(fd); 00137 fd = -1; 00138 mmap_size = 0; 00139 return NULL; 00140 } 00141 00142 // Now create the actual object in the shared-memory buffer. 00143 return new(shared_mem) SubprocessWindowBuffer(temp); 00144 } 00145 00146 //////////////////////////////////////////////////////////////////// 00147 // Function: SubprocessWindowBuffer::destroy_buffer 00148 // Access: Public, Static 00149 // Description: Destroys a buffer object created via a previous call 00150 // to new_buffer(). This destructs objects within the 00151 // buffer, unmaps the shared memory, and closes the file 00152 // descriptor. 00153 //////////////////////////////////////////////////////////////////// 00154 void SubprocessWindowBuffer:: 00155 destroy_buffer(int fd, size_t mmap_size, const string &filename, 00156 SubprocessWindowBuffer *buffer) { 00157 buffer->~SubprocessWindowBuffer(); 00158 close_buffer(fd, mmap_size, filename, buffer); 00159 00160 // Now we can unlink the file. 00161 unlink(filename.c_str()); 00162 } 00163 00164 //////////////////////////////////////////////////////////////////// 00165 // Function: SubprocessWindowBuffer::open_buffer 00166 // Access: Public, Static 00167 // Description: Call this method to open a reference to an existing 00168 // buffer in shared memory space. Supply the temporary 00169 // filename returned by new_buffer(), above (presumably 00170 // from the parent process). 00171 // 00172 // This method will mmap the required shared-memory 00173 // buffer and return a SubprocessWindowBuffer allocated 00174 // within that shared memory, or NULL if there is some 00175 // failure. The caller must retain fd, mmap_size, and 00176 // filename and eventually pass all three to 00177 // close_buffer(). 00178 //////////////////////////////////////////////////////////////////// 00179 SubprocessWindowBuffer *SubprocessWindowBuffer:: 00180 open_buffer(int &fd, size_t &mmap_size, const string &filename) { 00181 mmap_size = 0; 00182 00183 fd = open(filename.c_str(), O_RDWR); 00184 if (fd == -1) { 00185 perror(filename.c_str()); 00186 return NULL; 00187 } 00188 00189 // Check that the disk file is large enough. 00190 off_t file_size = lseek(fd, 0, SEEK_END); 00191 if (file_size < sizeof(SubprocessWindowBuffer)) { 00192 cerr << filename << " not large enough.\n"; 00193 close(fd); 00194 fd = -1; 00195 return NULL; 00196 } 00197 00198 // First, map enough memory to read the buffer object. 00199 size_t initial_size = sizeof(SubprocessWindowBuffer); 00200 void *shared_mem = mmap(NULL, initial_size, PROT_READ, 00201 MAP_SHARED, fd, 0); 00202 if (shared_mem == (void *)-1) { 00203 perror("mmap"); 00204 cerr << "Couldn't map.\n"; 00205 close(fd); 00206 fd = -1; 00207 return NULL; 00208 } 00209 00210 SubprocessWindowBuffer *temp = (SubprocessWindowBuffer *)shared_mem; 00211 if (!temp->verify_magic_number()) { 00212 cerr << "Not a subprocess window buffer: " << filename << "\n"; 00213 munmap(shared_mem, initial_size); 00214 close(fd); 00215 fd = -1; 00216 return NULL; 00217 } 00218 00219 00220 mmap_size = temp->_mmap_size; 00221 00222 // Now unmap that and remap the proper-size buffer. 00223 munmap(shared_mem, initial_size); 00224 00225 if (file_size < mmap_size) { 00226 cerr << filename << " not large enough.\n"; 00227 close(fd); 00228 fd = -1; 00229 return NULL; 00230 } 00231 00232 shared_mem = mmap(NULL, mmap_size, PROT_READ | PROT_WRITE, 00233 MAP_SHARED, fd, 0); 00234 if (shared_mem == (void *)-1) { 00235 perror("mmap"); 00236 cerr << "Couldn't map 2.\n"; 00237 return NULL; 00238 } 00239 00240 // Now that we've successfully opened and mapped the file, we can 00241 // safely delete it from the file system. 00242 00243 // Actually, unlinking it now prevents us from detaching and 00244 // reattaching to the same file later. Boo. 00245 // unlink(filename.c_str()); 00246 00247 SubprocessWindowBuffer *buffer = (SubprocessWindowBuffer *)shared_mem; 00248 assert(buffer->_mmap_size == mmap_size); 00249 return buffer; 00250 } 00251 00252 //////////////////////////////////////////////////////////////////// 00253 // Function: SubprocessWindowBuffer::close_buffer 00254 // Access: Public, Static 00255 // Description: Closes a buffer object created via a previous call 00256 // to open_buffer(). This unmaps the shared memory 00257 // and closes the file descriptor, but does not molest 00258 // the shared buffer itself. 00259 //////////////////////////////////////////////////////////////////// 00260 void SubprocessWindowBuffer:: 00261 close_buffer(int fd, size_t mmap_size, const string &filename, 00262 SubprocessWindowBuffer *buffer) { 00263 munmap((void *)buffer, mmap_size); 00264 close(fd); 00265 } 00266 00267 //////////////////////////////////////////////////////////////////// 00268 // Function: SubprocessWindowBuffer::verify_magic_number 00269 // Access: Public 00270 // Description: Returns true if the buffer's magic number matches, 00271 // false otherwise. 00272 //////////////////////////////////////////////////////////////////// 00273 bool SubprocessWindowBuffer:: 00274 verify_magic_number() const { 00275 return (memcmp(_this_magic, _magic_number, magic_number_length) == 0); 00276 }