rllib  1
rlsharedmemory.cpp
Go to the documentation of this file.
00001 /***************************************************************************
00002                           rlsharedmemory.cpp  -  description
00003                              -------------------
00004     begin                : Tue Jan 02 2001
00005     copyright            : (C) 2001 by Rainer Lehrig
00006     email                : lehrig@t-online.de
00007  ***************************************************************************/
00008 
00009 /***************************************************************************
00010  *                                                                         *
00011  *   This library is free software; you can redistribute it and/or modify  *
00012  *   it under the terms of the GNU LESSER GENERAL PUBLIC LICENSE as        *
00013  *   published by the Free Software Foundation                             *
00014  *                                                                         *
00015  ***************************************************************************/
00016 #include "rlsharedmemory.h"
00017 #include <stdio.h>
00018 #include <stdlib.h>
00019 #include <string.h>
00020 #ifndef RLWIN32
00021 #include <unistd.h>
00022 #endif
00023 
00024 #ifdef RLUNIX
00025 #include <sys/ipc.h>
00026 #include <sys/shm.h>
00027 #endif
00028 
00029 #ifdef __VMS
00030 #include <starlet.h>
00031 #include <lib$routines.h>
00032 #include <descrip.h>
00033 #include <ssdef.h>
00034 #include <syidef.h>
00035 #include <secdef.h>
00036 #include <rms.h>
00037 #include <errno.h>
00038 #include <psldef.h>
00039 #include <dvidef.h>
00040 typedef struct
00041 {
00042   long start;
00043   long end;
00044 }
00045 ADD;
00046 #endif
00047 
00048 #ifdef RLWIN32
00049 #include <windows.h>
00050 #endif
00051 
00052 static void myinit(pthread_mutex_t *mutex)
00053 {
00054   int *cnt = (int *) mutex;
00055   *cnt = 0;
00056 }
00057 
00058 static void mylock(pthread_mutex_t *mutex, int increment)
00059 {
00060   volatile int *cnt = (int *) mutex;
00061   while(1)
00062   {
00063 retry:
00064     if(*cnt == 0)
00065     { // try to lock the counter
00066       (*cnt) += increment;
00067       if(*cnt > 1)
00068       {
00069         (*cnt) -= increment;
00070         goto retry; // another process also wanted to lock the counter
00071       }
00072       return;       // now we can do it
00073     }
00074     rlwthread_sleep(1);
00075   }
00076 }
00077 
00078 static void myunlock(pthread_mutex_t *mutex)
00079 {
00080   int *cnt = (int *) mutex;
00081   if(*cnt > 0) (*cnt)--;
00082 }
00083 
00084 rlSharedMemory::rlSharedMemory(const char *shmname, unsigned long Size, int rwmode)
00085 {
00086 #ifdef RLUNIX
00087   struct shmid_ds buf;
00088   FILE *fp;
00089   int file_existed;
00090 
00091   status  = OK;
00092   name = new char[strlen(shmname)+1];
00093   strcpy(name,shmname);
00094   size    = Size + sizeof(*mutex);
00095 
00096   // create file
00097   file_existed = 1;
00098   fp = fopen(name,"r");
00099   if(fp == NULL)
00100   {
00101     file_existed = 0;
00102     fp = fopen(name,"w");
00103     if(fp == NULL)     
00104     {
00105       int ret; 
00106       char buf[1024];
00107       sprintf(buf,"could not write shm=%s\n",shmname);
00108       ret = ::write(1,buf,strlen(buf));
00109       if(ret < 0) exit(-1);
00110       sprintf(buf,"you have to run this program as root !!!\n");
00111       ret = ::write(1,buf,strlen(buf));
00112       if(ret < 0) exit(-1);
00113       status=ERROR_FILE;
00114       exit(-1);
00115     }
00116   }
00117   fclose(fp);
00118 
00119   // old stuff, without suggestions from Stefan Lievens 
00120   //shmkey  = ftok(name,0);
00121   //
00122   //id  = shmget(shmkey, size, IPC_CREAT);
00123 
00124   //shmkey  = ftok(name, 'R');
00125   shmkey  = ftok(name, 'b');
00126 
00127   //id  = shmget(shmkey, size, 0600 | IPC_CREAT);
00128   id  = shmget(shmkey, size, rwmode | IPC_CREAT);
00129   if(id < 0)           { status=ERROR_SHMGET; return; }
00130 
00131   base_adr = (char *) shmat(id,NULL,0);
00132   if(base_adr == NULL) { status=ERROR_SHMAT;  return; }
00133 
00134   if(shmctl(id, IPC_STAT, &buf) != 0) { status=ERROR_SHMCTL; return; };
00135 
00136   mutex     = (pthread_mutex_t *) base_adr;
00137   user_adr  = base_adr + sizeof(*mutex);
00138   //if(file_existed == 0) rlwthread_mutex_init(mutex,NULL);
00139   if(file_existed == 0) myinit(mutex);
00140 #endif
00141 
00142 #ifdef __VMS
00143   int file_existed = 0;
00144   long ret,fd,page_size,pagelets,pagelet_size,file_block_size,flags,item,ident[2];
00145   FILE *fp;
00146   ADD  add_in,add_ret;
00147   struct dsc$descriptor_s section_name;
00148   struct FAB fab;
00149 
00150   status  = OK;
00151   name = new char[strlen(shmname)+1];
00152   strcpy(name,shmname);
00153   size    = Size + sizeof(*mutex);
00154   // The file block size is fixed
00155   file_block_size = 512; // Bytes
00156   // Get the page size
00157   item = SYI$_PAGE_SIZE;
00158   ret = lib$getsyi( &item       ,
00159                     &page_size  ,
00160                     0           ,
00161                     0           ,
00162                     0           ,
00163                     0
00164                    );
00165   if(ret != SS$_NORMAL) { status=ERROR_FILE; return; }
00166   // Fill descriptor for section name
00167   section_name.dsc$w_length  = strlen(name);
00168   section_name.dsc$a_pointer = name;
00169   section_name.dsc$b_dtype   = DSC$K_DTYPE_T;
00170   section_name.dsc$b_class   = DSC$K_CLASS_S;
00171   // The pagelet size is fixed
00172   pagelet_size = 512; // Bytes
00173   // Get memory
00174   if(size % page_size == 0) pagelets = size / pagelet_size;
00175   else                      pagelets = (size / page_size + 1) * (page_size / pagelet_size);
00176   ret = sys$expreg(pagelets,&add_ret,0,0);
00177   if(ret != SS$_NORMAL) { status=ERROR_FILE; return; }
00178   // Set the addresses
00179   base_adr = (char *) add_ret.start;
00180   user_adr = base_adr + sizeof(*mutex);
00181   mutex    = (pthread_mutex_t *) base_adr;
00182   if(base_adr == NULL) { status=ERROR_SHMAT;  return; }
00183   // Fill the fab
00184   fab = cc$rms_fab;                       // Initialize fab
00185   fab.fab$b_fac = fab.fab$b_fac | FAB$M_PUT | FAB$M_DEL | FAB$M_GET | FAB$M_UPD;
00186   fab.fab$l_fna = name;
00187   fab.fab$b_fns = strlen(name);
00188   fab.fab$l_fop = fab.fab$l_fop
00189                       | FAB$M_CIF            // create file if not existent
00190                       | FAB$M_CTG            // contiguous
00191                       | FAB$M_UFO;           // user open
00192   fab.fab$b_shr =   fab.fab$b_shr            // shareble access
00193                       | FAB$M_SHRPUT
00194                       | FAB$M_UPI;
00195   fab.fab$l_alq = pagelets * pagelet_size / file_block_size;
00196   // Open the section file
00197   ret = sys$create (&fab);
00198   if(ret != RMS$_NORMAL && ret != RMS$_CREATED)
00199   {
00200     sys$close (&fab);
00201     status=ERROR_FILE;
00202     return;
00203   }
00204   // Set the channel
00205   fd = fab.fab$l_stv;
00206   // Fill the input address
00207   add_in.start = add_ret.start;
00208   add_in.end   = add_ret.end;
00209   // Clear ident
00210   ident[0] = 0;
00211   ident[1] = 0;
00212   // Set flags
00213   flags = 0;
00214   flags = SEC$M_GBL | SEC$M_WRT | SEC$M_PERM;
00215   // Create and map the section
00216   ret = sys$crmpsc(&add_in ,&add_ret,
00217                      (long)0       ,  // acmode
00218                      flags         ,  // flags
00219                      &section_name ,  // gsdnam
00220                      &ident        ,  // ident
00221                      (long)0       ,  // relpag
00222                      (short)fd     ,  // chan
00223                      pagelets      ,  // pagcnt
00224                      (long)0       ,  // vbn
00225                      (long)0       ,  // prot
00226                      (long)0          // pfc
00227                    );
00228   if(ret != SS$_NORMAL && ret != SS$_CREATED)
00229   {
00230     sys$close(&fab);
00231     status=ERROR_FILE;
00232     return;
00233   }
00234   // Test the section addresses
00235   if(add_in.start != add_ret.start || add_in.end != add_ret.end)
00236   {
00237     sys$close(&fab);
00238     status=ERROR_FILE;
00239     return;
00240   }
00241   // Close the section file
00242   ret = sys$close(&fab);
00243   // rlwthread_mutex_init(mutex,NULL);
00244   if(file_existed == 0) myinit(mutex);
00245 #endif
00246 
00247 #ifdef RLWIN32
00248   HANDLE hFile, hShmem;
00249   int file_existed;
00250 
00251   status  = OK;
00252   name = new char[strlen(shmname)+1];
00253   strcpy(name,shmname);
00254   size    = Size + sizeof(*mutex);
00255 
00256   file_existed = 1;
00257   hFile = CreateFile(name,
00258                      GENERIC_READ | GENERIC_WRITE,
00259                      FILE_SHARE_READ | FILE_SHARE_WRITE,
00260                      NULL,
00261                      OPEN_EXISTING,
00262                      FILE_ATTRIBUTE_NORMAL,
00263                      NULL
00264                      );
00265   if(hFile ==  INVALID_HANDLE_VALUE)
00266   {
00267     file_existed = 0;
00268     hFile = CreateFile(name,
00269                        GENERIC_READ | GENERIC_WRITE,
00270                        FILE_SHARE_READ | FILE_SHARE_WRITE,
00271                        NULL,
00272                        CREATE_NEW,
00273                        FILE_ATTRIBUTE_NORMAL,
00274                        NULL
00275                        );
00276   }
00277   if(hFile == INVALID_HANDLE_VALUE) { status=ERROR_FILE; return; }
00278   hShmem = CreateFileMapping(
00279     hFile,
00280     NULL,                // no security attributes
00281     PAGE_READWRITE,      // read/write access
00282     0,                   // size: high 32-bits
00283     size,                // size: low 32-bits
00284     NULL);               // name of map object
00285   if(hShmem == NULL) { status=ERROR_FILE; return; }
00286   base_adr = (char *) MapViewOfFile(
00287     hShmem,              // object to map view of
00288     FILE_MAP_WRITE,      // read/write access
00289     0,                   // high offset:  map from
00290     0,                   // low offset:   beginning
00291     0);                  // default: map entire file
00292   if(base_adr == NULL) { status=ERROR_FILE; return; }
00293   id     = (int) hShmem;
00294   shmkey = (int) hFile;
00295   mutex     = (pthread_mutex_t *) base_adr;
00296   user_adr  = base_adr + sizeof(*mutex);
00297   if(file_existed == 0) rlwthread_mutex_init(mutex,NULL);
00298 #endif
00299   if(rwmode == 0) return; // no warning of unused parameter
00300 }
00301 
00302 rlSharedMemory::~rlSharedMemory()
00303 {
00304   delete [] name;
00305 #ifdef RLWIN32
00306   if(status != OK) return;
00307   CloseHandle((HANDLE) id);
00308   CloseHandle((HANDLE) shmkey);
00309 #endif
00310 }
00311 
00312 int rlSharedMemory::deleteSharedMemory()
00313 {
00314 #ifdef RLUNIX
00315   struct shmid_ds buf;
00316   if(status != OK) return -1;
00317   rlwthread_mutex_destroy(mutex);
00318   shmctl(id, IPC_RMID, &buf);
00319   size = 0;
00320   return 0;
00321 #endif
00322 
00323 #ifdef __VMS
00324   int ret;
00325   ADD add_in,add_ret;
00326   struct dsc$descriptor_s section_name;
00327 
00328   if(status != OK) return -1;
00329   rlwthread_mutex_destroy(mutex);
00330   // Fill descriptor for section name
00331   section_name.dsc$w_length  = strlen(name);
00332   section_name.dsc$a_pointer = name;
00333   section_name.dsc$b_dtype   = DSC$K_DTYPE_T;
00334   section_name.dsc$b_class   = DSC$K_CLASS_S;
00335   // Delete the section
00336   ret = sys$dgblsc(0,&section_name,0);
00337   if(ret != SS$_NORMAL) return -1;
00338   // Fill the input address
00339   add_in.start = (long) base_adr;
00340   add_in.end   = (long) base_adr + size;
00341   // Free the memory
00342   ret = sys$deltva(&add_in,&add_ret,0);
00343   if(ret != SS$_NORMAL) return -1;
00344   // Test the section addresses
00345   if(add_in.start != add_ret.start || add_in.end != add_ret.end) return -1;
00346   return 0;
00347 #endif
00348 
00349 #ifdef RLWIN32
00350   if(status != OK) return -1;
00351   rlwthread_mutex_destroy(mutex);
00352   UnmapViewOfFile(base_adr);
00353   CloseHandle((HANDLE) id);
00354   CloseHandle((HANDLE) shmkey);
00355   status = ~OK;
00356   return 0;
00357 #endif
00358 }
00359 
00360 int rlSharedMemory::write(unsigned long offset, const void *buf, int len)
00361 {
00362   void *ptr;
00363   if(status != OK)      return -1;
00364   if(len <= 0)          return -1;
00365   if(offset+len > size) return -1;
00366   ptr = user_adr + offset;
00367 #ifdef RLWIN32
00368   rlwthread_mutex_lock(mutex);   // Linux and OpenVMS don't support PTHREAD_PROCESS_SHARED (windows does not support pthread at all)
00369 #else
00370   mylock(mutex,1);
00371 #endif
00372   memcpy(ptr,buf,len);
00373 #ifdef RLWIN32
00374   rlwthread_mutex_unlock(mutex); // Linux and OpenVMS don't support PTHREAD_PROCESS_SHARED (windows does not support pthread at all)
00375 #else
00376   myunlock(mutex);
00377 #endif
00378   return len;
00379 }
00380 
00381 int rlSharedMemory::read(unsigned long offset, void *buf, int len)
00382 {
00383   void *ptr;
00384   if(status != OK)      return -1;
00385   if(len <= 0)          return -1;
00386   if(offset+len > size) return -1;
00387   ptr = user_adr + offset;
00388 #ifdef RLWIN32
00389   rlwthread_mutex_lock(mutex);   // Linux and OpenVMS don't support PTHREAD_PROCESS_SHARED (windows does not support pthread at all)
00390 #else
00391   mylock(mutex,1);
00392 #endif
00393   memcpy(buf,ptr,len);
00394 #ifdef RLWIN32
00395   rlwthread_mutex_unlock(mutex); // Linux and OpenVMS don't support PTHREAD_PROCESS_SHARED (windows does not support pthread at all)
00396 #else
00397   myunlock(mutex);
00398 #endif
00399   return len;
00400 }
00401 
00402 int rlSharedMemory::readInt(unsigned long offset, int index)
00403 {
00404   int val;
00405   if(index < 0) return -1;
00406   read(offset+index*sizeof(val),&val,sizeof(val));
00407   return val;
00408 }
00409 
00410 int rlSharedMemory::readShort(unsigned long offset, int index)
00411 {
00412   short int val;
00413   if(index < 0) return -1;
00414   read(offset+index*sizeof(val),&val,sizeof(val));
00415   return val;
00416 }
00417 
00418 int rlSharedMemory::readByte(unsigned long offset, int index)
00419 {
00420   char val;
00421   if(index < 0) return -1;
00422   read(offset+index*sizeof(val),&val,sizeof(val));
00423   return val;
00424 }
00425 
00426 float rlSharedMemory::readFloat(unsigned long offset, int index)
00427 {
00428   float val;
00429   if(index < 0) return -1;
00430   read(offset+index*sizeof(val),&val,sizeof(val));
00431   return val;
00432 }
00433 
00434 int rlSharedMemory::writeInt(unsigned long offset, int index, int val)
00435 {
00436   int ret;
00437   if(index < 0) return -1;
00438   ret = write(offset+index*sizeof(val),&val,sizeof(val));
00439   return ret;
00440 }
00441 
00442 int rlSharedMemory::writeShort(unsigned long offset, int index, int val)
00443 {
00444   int ret;
00445   short int val2;
00446 
00447   if(index < 0) return -1;
00448   val2 = (short int) val;
00449   ret = write(offset+index*sizeof(val2),&val2,sizeof(val2));
00450   return ret;
00451 }
00452 
00453 int rlSharedMemory::writeByte(unsigned long offset, int index, unsigned char val)
00454 {
00455   int ret;
00456   if(index < 0) return -1;
00457   ret = write(offset+index*sizeof(val),&val,sizeof(val));
00458   return ret;
00459 }
00460 
00461 int rlSharedMemory::writeFloat(unsigned long offset, int index, float val)
00462 {
00463   int ret;
00464   if(index < 0) return -1;
00465   ret = write(offset+index*sizeof(val),&val,sizeof(val));
00466   return ret;
00467 }
00468 
00469 void *rlSharedMemory::getUserAdr()
00470 {
00471   return (void *) user_adr;
00472 }
00473 
00474 int rlSharedMemory::shmKey()
00475 {
00476   return shmkey;
00477 }
00478 
00479 int rlSharedMemory::shmId()
00480 {
00481   return id;
00482 }
00483