The VisAO Camera
sharedim_stack.cpp
Go to the documentation of this file.
1 /************************************************************
2  * sharedim_stack.cpp
3  *
4  * Author: Jared R. Males (jrmales@email.arizona.edu)
5  *
6  * Definitions for the shared image circular buffer.
7  *
8  * Developed as part of the Magellan Adaptive Optics system.
9  ************************************************************/
10 
11 /** \file sharedim_stack.cpp
12  * \author Jared R. Males
13  * \brief Definitions for the shared image circular buffer.
14  *
15  */
16 
17 #include "sharedim_stack.h"
18 
19 #ifndef ERROR_REPORT
20 #define ERROR_REPORT(er) if(global_error_report) (*global_error_report)(er,__FILE__,__LINE__);
21 #endif
22 
23 #ifndef LOG_INFO
24 #define LOG_INFO(li) if(global_log_info) (*global_log_info)(li);
25 #endif
26 
28 {
29  shmemptr = 0;
30  shmemkey = -1;
31  shmemid = 0;
32  shmemsz = 0;
33 
34  header = 0;
35 
36  image_list = 0;
37 
38  next_last_image = -1;
39 }
40 
42 {
43  if(shmemptr > 0)
44  {
45  return header->n_images;
46  }
47  else return -1;
48 }
49 
51 {
52  if(shmemptr > 0)
53  {
55  header->max_n_images = mni;
56 
57  //Calculate the offset of the first image
58  image_list[0] = sizeof(sharedim_stack_header) + mni*sizeof(intptr_t);
59 
60  return 0;
61  }
62  else return -1;
63 }
64 
66 {
67  if(shmemptr > 0)
68  {
69  return header->max_n_images;
70  }
71  else return -1;
72 }
73 
75 {
76  if(shmemptr > 0)
77  {
78  return header->last_image;
79  }
80  else return -1;
81 }
82 
84 {
85  sharedim * previm;
86 
87  if(shmemptr > 0)
88  {
89  if(imno > header->n_images)
90  {
91  ERROR_REPORT("Can't calculate image offset without previous image.");
92  return 0;
93  }
94 
95  if(imno == 0) //this is easy
96  {
97  return (sharedim *)((intptr_t)header + image_list[0]);
98  }
99 
100  //The previous image is set up already, so we use its image_list entry
101  previm = (sharedim *)((intptr_t)header + image_list[imno-1]);
102  sharedim * p0 = previm;
103 
104  size_t offset = (sizeof(sharedim) + (previm->nx*previm->ny*sizeof(IMDATA_TYPE)));
105  previm = (sharedim *)((intptr_t) previm + (size_t) offset);
106 
107  return previm;
108  }
109  else return 0; //can't do anything
110 }
111 
112 int sharedim_stack::create_shm(key_t mkey, size_t sz)
113 {
114  int rv;
115  std::ostringstream oss;
116 
117  errno = 0;
118  if((shmemid = shmget(mkey, sz, IPC_CREAT | 0666))<0)
119  {
120  shmemid = shmget(mkey, 1, 0666);
121 
122  //If it failed, try to remove the shmem block and recreate it.
123 
124  if(shmctl(shmemid, IPC_RMID, 0) < 0)
125  {
126  oss << "Could not remove shared memory with key " << mkey << ".";
127  ERROR_REPORT(oss.str().c_str());
128  return -1;
129  }
130  oss << "Removed shared memory with key " << mkey << ".";
131  LOG_INFO(oss.str().c_str());
132  oss.str("");
133 
134  if((shmemid = shmget(mkey, sz, IPC_CREAT | 0666))<0)
135  {
136  oss << "Could not create shared memory with key " << mkey << ".";
137  ERROR_REPORT(oss.str().c_str());
138  return -1;
139  }
140  }
141 
142  oss << "Shared memory created with key " << mkey << ".";
143  LOG_INFO(oss.str().c_str());
144 
145  rv = attach_shm(mkey);
146  //std::cout << sz << "\n";
147  //std::cout << shmemsz << "\n";
148 
149  return rv;
150 }
151 
152 int sharedim_stack::create_shm(key_t mkey, int nims, size_t sz)
153 {
154  if(create_shm(mkey, sizeof(sharedim_stack_header) +nims*sizeof(intptr_t)+ sz) < 0)
155  {
156  return -1;
157  }
158 
159  set_max_n_images(nims);
160  header->last_image = -1;
161  header->last_image_abs = -1;
162  header->n_images = 0;
163 
164  return 0;
165 }
166 
168 {
169  std::ostringstream oss;
170  static int reported = 0;
171  if(shmemid == 0)
172  {
173  if((shmemid = shmget(mkey, 0, 0666))<0)
174  {
175  if(!reported)
176  {
177  oss << "Could not get shared memory with key " << mkey;
178  ERROR_REPORT(oss.str().c_str());
179  }
180  reported = 1;
181  return -1;
182  }
183  }
184 
185  if ((shmemptr = shmat(shmemid, 0, 0)) == (char *) -1)
186  {
187  oss << "Could not attach shared memory with key " << mkey;
188  ERROR_REPORT(oss.str().c_str());
189  return -1;
190  }
191 
192  if (shmctl(shmemid, IPC_STAT, &shmstats) < 0)
193  {
194  oss << "Could not get shared memory stats with key " << mkey;
195  ERROR_REPORT(oss.str().c_str());
196  return -1;
197  }
198 
199  shmemkey = mkey;
200  shmemsz = shmstats.shm_segsz;
201 
202  oss << "Attached to shared memory with key " << mkey << " of size: " << shmemsz;
203  LOG_INFO(oss.str().c_str());
204 
206 
207  image_list = (intptr_t *) ((intptr_t) shmemptr + sizeof(sharedim_stack_header));
208 
209  return 0;
210 }
211 
213 {
214  sharedim * nextim;
215  sharedim * nextnextim;
216  size_t offset;
217 
218  if(!shmemptr) return 0;
219 
220  //First see if we need to even check anything, or if we need to just wrap around
221  if(header->last_image + 1 < header->max_n_images)
222  {
223  nextim = calc_im_pos((header->last_image) + 1);
224  if(nextim == 0)
225  {
226  std::cerr << "Error in calc_im_pos. Last image " << " " <<header->last_image<< std::endl;
227  return 0;
228  }
229 
230  offset = sizeof(sharedim) + ((intptr_t)nx)*((intptr_t)ny)*sizeof(IMDATA_TYPE);
231  //previm = (sharedim *)((intptr_t) previm + (size_t) offset);
232 
233 
234  nextnextim = (sharedim *)((intptr_t)nextim + offset);
235 
236  /* std::cout << sizeof(sharedim) << "\n";
237  * std::cout << sizeof(IMDATA_TYPE) << "\n";
238  * std::cout << nx << "\n";
239  * std::cout << ny << "\n";
240  * std::cout << shmemsz << "\n";
241  * std::cout << (intptr_t) nextnextim << "\n";
242  * std::cout << (intptr_t) shmemptr << "\n";
243  * std::cout << (intptr_t)nextnextim - (intptr_t) shmemptr<< "\n";
244  */
245  //Check if we'll exceed the shared memory size, wrap around if so.
246  if( (intptr_t)nextnextim - (intptr_t) shmemptr > (intptr_t)(shmemsz-1))
247  {
248  std::cerr << "Wrapping " << (header->last_image) + 1 << " " << (intptr_t)nextnextim - (intptr_t) shmemptr << "\n";
249  next_last_image = 0;
250  nextim = (sharedim *)((intptr_t)header + image_list[0]);
251  //We also need to reset max_n_images
252  //header->max_n_images = header->last_image;
253  }
254  else
255  {
256  //std::cerr << "B\n";
257  //Nope, just use the next available image
258  next_last_image = header->last_image + 1;
259  //if(header->n_images <= next_last_image) header->n_images++;
260  image_list[next_last_image] = (intptr_t)nextim-(intptr_t)header;
261  }
262  }
263  else //Just wrapping around
264  {
265  //std::cerr << "C\n";
266  nextim = (sharedim *)((intptr_t)header + (intptr_t)image_list[0]);
267  next_last_image = 0;
268  }
269 
270  //Now fill in the structure
271  nextim->nx = nx;
272  nextim->ny = ny;
273  nextim->imdata = (IMDATA_TYPE *) ((intptr_t)nextim+sizeof(sharedim)); //this pointer is only valid in the calling process
274 
275  return nextim;
276 }
277 
279 {
280  header->last_image = next_last_image;
281  if(header->n_images <= next_last_image) header->n_images++;
282  header->last_image_abs++;
283  return 0;
284 }
285 
287 {
288  sharedim *simraw, sim;
289 
290  //Initialize the sharedim struct (should have an initializer)
291  sim.nx =0;
292  sim.ny =0;
293  sim.depth = 0;
294  sim.imdata = 0;
295 
296  //std::cout << "get_image parms:" << imno << " " << header->n_images << " " << header->max_n_images << "\n";
297  if(imno < header->n_images)
298  {
299  simraw = (sharedim *)((intptr_t) header + (intptr_t) image_list[imno]);
300 
301  //std::cout << "nx " << simraw->nx << "\n";
302 
303  sim.nx = simraw->nx;
304  sim.ny = simraw->ny;
305  sim.depth = simraw->depth;
306  sim.frameNo = simraw->frameNo;
307  sim.frame_time = simraw->frame_time;
308  sim.imdata = (IMDATA_TYPE *) ((intptr_t)simraw + sizeof(sharedim));
309  }
310  //else std::cout << "what the f?\n";
311  return sim;
312 
313 }
key_t shmemkey
The key used to lookup the shared memory.
int enable_next_image()
Increments last_image.
size_t shmemsz
Size of the shared memory block.
int set_max_n_images(int mni)
Sets max_n_images in the header.
struct shmid_ds shmstats
Used to retrieve shared memory block size.
sharedim_stack_header * header
Convenient pointer to the stack header, has same value as shmemptr.
sharedim< IMDATA_TYPE > * calc_im_pos(int imno)
Calculates the offset of the image given by imno, takes into account max_n_images and available space...
sharedim< IMDATA_TYPE > * set_next_image(int nx, int ny)
Sets the next image, and returns a pointer to it, but does not increment last_image.
Convenience structure for the stack header.
int attach_shm(key_t mkey)
Attachess the shared memory. A Reader process should start here.
int shmemid
The shared memory id.
sharedim< IMDATA_TYPE > get_image(int imno)
Gets an image, as a sharedim structure, with the imdata pointer properly set for the calling process...
void * shmemptr
The pointer to the shared memory block.
Convenience structure for an image.
int create_shm(key_t mkey, size_t sz)
For the writer process, creates then attaches the shared memory.
Declarations for the shared image circular buffer.
intptr_t * image_list
Convenient pointer to the list of image offsets.
sharedim_stack()
Constructor.
int get_n_images()
Returns the value of n_images currently in the header.
int get_last_image()
Returns the value of last_image currently in the header.
int get_max_n_images()
Returns the value of max_n_images currently in the header.