The VisAO Camera
sharedim_stack.h
Go to the documentation of this file.
1 /************************************************************
2  * sharedim_stack.h
3  *
4  * Author: Jared R. Males (jrmales@email.arizona.edu)
5  *
6  * Declarations for the shared image circular buffer.
7  *
8  * Developed as part of the Magellan Adaptive Optics system.
9  ************************************************************/
10 
11 /** \file sharedim_stack.h
12  * \author Jared R. Males
13  * \brief Declarations for the shared image circular buffer.
14  *
15  */
16 
17 
18 #ifndef __SHAREDIM_STACK_H__
19 #define __SHAREDIM_STACK_H__
20 
21 #define IM0_OFFSET (sizeof(sharedim_stack_header) + header->n_images*sizeof(int))
22 #define IMD_OFFSET (2*sizeof(int)+sizeof(int *))
23 
24 #include <sys/shm.h>
25 #include <sys/time.h>
26 
27 #include <iostream>
28 #include <sstream>
29 
30 #include "libvisao.h"
31 
32 //#define IMDATA_TYPE short
33 
34 
35 /************************************************/
36 /* The sharedim_stack layout:
37  * Header:
38  * int max_n_images
39  * int n_images
40  * int last_image
41  * int last_image_abs
42  * Image offset list:
43  * int offset 0 <This is the memory offset from position 0 to the position of the first image>
44  * int offset 1
45  * . . .
46  * int offset max_n_images-1
47  * Images (struct sharedim):
48  * int nx
49  * int ny
50  * int depth
51  * int frameNo
52  * timeval frame_time
53  * IMDATA_TYPE * imdata
54  * IMDATA_TYPE imdata[0]
55  * . . .
56  * IMDATA_TYPE imdata[nx*ny-1]
57  * (next image)
58  */
59 
60 #ifndef ERROR_REPORTSIM
61 #define ERROR_REPORTSIM(er) if(global_error_report) (*global_error_report)(er,__FILE__,__LINE__);
62 #endif
63 
64 #ifndef LOG_INFOSIM
65 #define LOG_INFOSIM(li) if(global_log_info) (*global_log_info)(li);
66 #endif
67 
68 ///Convenience structure for an image
69 /** Do not use this to access a shared image unless it has been retrieved via sharedim_stack::get_image(int)
70  * so that the imdata pointer is set correctly for the calling process' memory map.
71  */
72 template <class IMDATA_TYPE> struct sharedim
73 {
74  int nx;
75  int ny;
76  int depth;
77  long frameNo;
78  int saved;
79  timeval frame_time;
80  timeval frame_time_dma;
81  IMDATA_TYPE * imdata;
82 };
83 
86 
87 ///Convenience structure for the stack header.
89 {
90  int max_n_images;
91  int n_images;
92  int last_image;
93  int last_image_abs;
94  int save_sequence; //A sequential number, updated when a new save sequence is desired.
95 
96 };
97 
98 ///Class to manage a stack of images in shared memory
99 /** Can be used by both the writer and the readers
100  */
101 template <class IMDATA_TYPE> class sharedim_stack
102 {
103 public:
104  sharedim_stack();///<Constructor
105 
106 protected:
107  void * shmemptr;///<The pointer to the shared memory block
108  key_t shmemkey;///<The key used to lookup the shared memory
109  int shmemid;///<The shared memory id
110  size_t shmemsz;///<Size of the shared memory block
111 
112  intptr_t * image_list;///<Convenient pointer to the list of image offsets
113 
114  struct shmid_ds shmstats;///<Used to retrieve shared memory block size.
115 
116 public:
117  sharedim_stack_header * header;///<Convenient pointer to the stack header, has same value as \ref shmemptr
118 
119  int next_last_image;
120 
121 public:
122  void * get_shmemptr(){return shmemptr;}
123  key_t get_shmemkey(){return shmemkey;}
124  int get_shmemid(){return shmemid;}
125  size_t get_shmemsz(){return shmemsz;}
126 
127 
128  int get_n_images();///<Returns the value of n_images currently in the header
129 
130  int set_max_n_images(int mni);///<Sets max_n_images in the header
131  int get_max_n_images();///<Returns the value of max_n_images currently in the header
132 
133  int get_last_image();///<Returns the value of last_image currently in the header
134  int get_last_image_abs(){return header->last_image_abs;}
135 
136  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.
137 
138  int set_saved(int imno, int sv); ///<Update the saved field of this image.
139 
140  int create_shm(key_t mkey, size_t sz);///<For the writer process, creates then attaches the shared memory.
141  int create_shm(key_t mkey, int nims, size_t imsz);///<For the writer process, creates then attaches the shared memory.
142  int attach_shm(key_t mkey);///<Attachess the shared memory. A Reader process should start here.
143 
144  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.
145  int enable_next_image();///<Increments last_image
146  sharedim<IMDATA_TYPE> get_image(int imno);///<Gets an image, as a sharedim structure, with the imdata pointer properly set for the calling process.
147 };
148 
149 template <class IMDATA_TYPE> sharedim_stack<IMDATA_TYPE>::sharedim_stack()
150 {
151  shmemptr = 0;
152  shmemkey = -1;
153  shmemid = 0;
154  shmemsz = 0;
155 
156  header = 0;
157 
158  image_list = 0;
159 
160  next_last_image = -1;
161 }
162 
163 template <class IMDATA_TYPE> int sharedim_stack<IMDATA_TYPE>::get_n_images()
164 {
165  if(shmemptr > 0)
166  {
167  return header->n_images;
168  }
169  else return -1;
170 }
171 
172 template <class IMDATA_TYPE> int sharedim_stack<IMDATA_TYPE>::set_max_n_images(int mni)
173 {
174  if(shmemptr > 0)
175  {
176  if(header == 0) header = (sharedim_stack_header *) shmemptr;
177  header->max_n_images = mni;
178 
179  //Calculate the offset of the first image
180  image_list[0] = sizeof(sharedim_stack_header) + mni*sizeof(intptr_t);
181 
182  return 0;
183  }
184  else return -1;
185 }
186 
187 template <class IMDATA_TYPE> int sharedim_stack<IMDATA_TYPE>::get_max_n_images()
188 {
189  if(shmemptr > 0)
190  {
191  return header->max_n_images;
192  }
193  else return -1;
194 }
195 
196 template <class IMDATA_TYPE> int sharedim_stack<IMDATA_TYPE>::get_last_image()
197 {
198  if(shmemptr > 0)
199  {
200  return header->last_image;
201  }
202  else return -1;
203 }
204 
205 template <class IMDATA_TYPE> int sharedim_stack<IMDATA_TYPE>::set_saved(int imno, int sv)
206 {
207  sharedim<IMDATA_TYPE> *simraw;
208 
209  if(imno < header->n_images)
210  {
211  simraw = (sharedim<IMDATA_TYPE> *)((intptr_t) header + (intptr_t) image_list[imno]);
212 
213  simraw->saved = sv;
214  return 0;
215  }
216 
217  return -1;
218 
219 }
220 
221 
222 template <class IMDATA_TYPE> sharedim<IMDATA_TYPE> * sharedim_stack<IMDATA_TYPE>::calc_im_pos(int imno)
223 {
224  sharedim<IMDATA_TYPE> * previm;
225 
226  if(shmemptr > 0)
227  {
228  if(imno > header->n_images)
229  {
230  ERROR_REPORTSIM("Can't calculate image offset without previous image.");
231  return 0;
232  }
233 
234  if(imno == 0) //this is easy
235  {
236  return (sharedim<IMDATA_TYPE> *)((intptr_t)header + image_list[0]);
237  }
238 
239  //The previous image is set up already, so we use its image_list entry
240  previm = (sharedim<IMDATA_TYPE> *)((intptr_t)header + image_list[imno-1]);
241 
242  //The correct way:
243  size_t offset = (sizeof(sharedim<IMDATA_TYPE>) + (previm->nx*previm->ny*sizeof(IMDATA_TYPE)));
244  previm = (sharedim<IMDATA_TYPE> *)((intptr_t) previm + (size_t) offset);
245 
246  return previm;
247  }
248  else return 0; //can't do anything
249 }
250 
251 template <class IMDATA_TYPE> int sharedim_stack<IMDATA_TYPE>::create_shm(key_t mkey, size_t sz)
252 {
253  int rv;
254  std::ostringstream oss;
255 
256  errno = 0;
257  if((shmemid = shmget(mkey, sz, IPC_CREAT | 0666))<0)
258  {
259  perror("shmget");
260  if(errno == EINVAL)
261  {
262  oss.str("");
263  oss << "shmget returned EINVAL. Check kernel SHMMAX paramter in /etc/sysctl.conf.";
264  oss << " sz = " << sz;
265  ERROR_REPORTSIM(oss.str().c_str());
266  return -1;
267  }
268 
269  shmemid = shmget(mkey, 1, 0666);
270 
271  //If it failed, try to remove the shmem block and recreate it.
272 
273  if(shmctl(shmemid, IPC_RMID, 0) < 0)
274  {
275  oss.str("");
276  oss << "Could not remove shared memory with key " << mkey << " and ID " << shmemid << ".";
277  ERROR_REPORTSIM(oss.str().c_str());
278  return -1;
279  }
280  oss << "Removed shared memory with key " << mkey << ".";
281  LOG_INFOSIM(oss.str().c_str());
282  oss.str("");
283 
284  if((shmemid = shmget(mkey, sz, IPC_CREAT | 0666))<0)
285  {
286  oss << "Could not create shared memory with key " << mkey << ".";
287  ERROR_REPORTSIM(oss.str().c_str());
288  return -1;
289  }
290  }
291 
292  oss << "Shared memory created with key " << mkey << ".";
293  LOG_INFOSIM(oss.str().c_str());
294 
295  rv = attach_shm(mkey);
296 
297  return rv;
298 }
299 
300 template <class IMDATA_TYPE> int sharedim_stack<IMDATA_TYPE>::create_shm(key_t mkey, int nims, size_t sz)
301 {
302  if(create_shm(mkey, sizeof(sharedim_stack_header) +nims*sizeof(intptr_t)+ sz) < 0)
303  {
304  return -1;
305  }
306 
307  set_max_n_images(nims);
308  header->last_image = -1;
309  header->last_image_abs = -1;
310  header->n_images = 0;
311 
312  return 0;
313 }
314 
315 template <class IMDATA_TYPE> int sharedim_stack<IMDATA_TYPE>::attach_shm(key_t mkey)
316 {
317  std::ostringstream oss;
318  static int reported = 0;
319  if(shmemid == 0)
320  {
321  if((shmemid = shmget(mkey, 0, 0666))<0)
322  {
323  if(!reported)
324  {
325  oss << "Could not get shared memory with key " << mkey;
326  ERROR_REPORTSIM(oss.str().c_str());
327  }
328  shmemid = 0;
329  reported = 1;
330  return -1;
331  }
332  }
333 
334  if ((shmemptr = shmat(shmemid, 0, 0)) == (char *) -1)
335  {
336  if(!reported)
337  {
338  oss << "Could not attach shared memory with key " << mkey;
339  ERROR_REPORTSIM(oss.str().c_str());
340  }
341  shmemptr = 0;
342  reported = 1;
343  return -1;
344  }
345 
346  if (shmctl(shmemid, IPC_STAT, &shmstats) < 0)
347  {
348  if(!reported)
349  {
350  oss << "Could not get shared memory stats with key " << mkey;
351  ERROR_REPORTSIM(oss.str().c_str());
352  }
353  reported = 1;
354  return -1;
355  }
356 
357  shmemkey = mkey;
358  shmemsz = shmstats.shm_segsz;
359 
360  oss << "Attached to shared memory with key " << mkey << " of size: " << shmemsz;
361  LOG_INFOSIM(oss.str().c_str());
362 
363  header = (sharedim_stack_header *) shmemptr;
364 
365  image_list = (intptr_t *) ((intptr_t) shmemptr + sizeof(sharedim_stack_header));
366 
367  return 0;
368 }
369 
370 template <class IMDATA_TYPE> sharedim<IMDATA_TYPE> * sharedim_stack<IMDATA_TYPE>::set_next_image(int nx, int ny)
371 {
372  sharedim<IMDATA_TYPE> * nextim;
373  sharedim<IMDATA_TYPE> * nextnextim;
374  size_t offset;
375 
376  if(!shmemptr) return 0;
377 
378  //First see if we need to even check anything, or if we need to just wrap around
379  if(header->last_image + 1 < header->max_n_images)
380  {
381  nextim = calc_im_pos((header->last_image) + 1);
382  if(nextim == 0)
383  {
384  std::cerr << "Error in calc_im_pos. Last image " << " " <<header->last_image<< std::endl;
385  return 0;
386  }
387 
388  offset = sizeof(sharedim<IMDATA_TYPE>) + ((intptr_t)nx)*((intptr_t)ny)*sizeof(IMDATA_TYPE);
389 
390  nextnextim = (sharedim<IMDATA_TYPE> *)((intptr_t)nextim + offset);
391 
392  //Check if we'll exceed the shared memory size, wrap around if so.
393  if( (intptr_t)nextnextim - (intptr_t) shmemptr > (intptr_t)(shmemsz-1))
394  {
395  std::cerr << "Wrapping " << (header->last_image) + 1 << " " << (intptr_t)nextnextim - (intptr_t) shmemptr << "\n";
396  next_last_image = 0;
397  nextim = (sharedim<IMDATA_TYPE>*)((intptr_t)header + image_list[0]);
398  }
399  else
400  {
401  //Nope, just use the next available image
402  next_last_image = header->last_image + 1;
403  image_list[next_last_image] = (intptr_t)nextim-(intptr_t)header;
404  }
405  }
406  else //Just wrapping around
407  {
408  nextim = (sharedim<IMDATA_TYPE> *)((intptr_t)header + (intptr_t)image_list[0]);
409  next_last_image = 0;
410  }
411 
412  //Now fill in the structure
413  nextim->nx = nx;
414  nextim->ny = ny;
415  nextim->frameNo = -1;
416  nextim->imdata = (IMDATA_TYPE *) ((intptr_t)nextim+sizeof(sharedim<IMDATA_TYPE>)); //this pointer is only valid in the calling process
417 
418  return nextim;
419 }
420 
421 template <class IMDATA_TYPE> int sharedim_stack<IMDATA_TYPE>::enable_next_image()
422 {
423  header->last_image = next_last_image;
424  if(header->n_images <= next_last_image) header->n_images++;
425  header->last_image_abs++;
426  return 0;
427 }
428 
429 template <class IMDATA_TYPE> sharedim<IMDATA_TYPE> sharedim_stack<IMDATA_TYPE>::get_image(int imno)
430 {
431  sharedim<IMDATA_TYPE> *simraw, sim;
432 
433  //Initialize the sharedim struct (should have an initializer)
434  sim.nx =0;
435  sim.ny =0;
436  sim.depth = 0;
437  sim.imdata = 0;
438 
439  if(imno < header->n_images)
440  {
441  simraw = (sharedim<IMDATA_TYPE> *)((intptr_t) header + (intptr_t) image_list[imno]);
442 
443  sim.nx = simraw->nx;
444  sim.ny = simraw->ny;
445  sim.depth = simraw->depth;
446  sim.frameNo = simraw->frameNo;
447  sim.frame_time = simraw->frame_time;
448  sim.frame_time_dma = simraw->frame_time_dma;
449  sim.saved = simraw->saved;
450  sim.imdata = (IMDATA_TYPE *) ((intptr_t)simraw + sizeof(sharedim<IMDATA_TYPE>));
451  }
452  return sim;
453 
454 }
455 
460 
461 #endif //__SHAREDIM_STACK_H__
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.
int set_saved(int imno, int sv)
Update the saved field of this image.
Class to manage a stack of images in shared memory.
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.
VisAO software utilitites, declarations.
int attach_shm(key_t mkey)
Attachess the shared memory. A Reader process should start here.
void * attach_shm(size_t *sz, key_t mkey, int shmemid)
Attach to a shared memory buffer and get its size.
Definition: libvisaoc.c:90
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.
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.