root/plugin/svipc/sysvipcwrappers.cpp

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. shmget
  2. shmat
  3. shmdt
  4. shmctl
  5. semget
  6. semop
  7. semtimedop
  8. semctl
  9. msgget
  10. msgsnd
  11. msgrcv
  12. msgctl

   1 /****************************************************************************
   2  *   Copyright (C) 2006-2010 by Jason Ansel, Kapil Arya, and Gene Cooperman *
   3  *   jansel@csail.mit.edu, kapil@ccs.neu.edu, gene@ccs.neu.edu              *
   4  *                                                                          *
   5  *   This file is part of the dmtcp/src module of DMTCP (DMTCP:dmtcp/src).  *
   6  *                                                                          *
   7  *  DMTCP:dmtcp/src is free software: you can redistribute it and/or        *
   8  *  modify it under the terms of the GNU Lesser General Public License as   *
   9  *  published by the Free Software Foundation, either version 3 of the      *
  10  *  License, or (at your option) any later version.                         *
  11  *                                                                          *
  12  *  DMTCP:dmtcp/src is distributed in the hope that it will be useful,      *
  13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of          *
  14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the           *
  15  *  GNU Lesser General Public License for more details.                     *
  16  *                                                                          *
  17  *  You should have received a copy of the GNU Lesser General Public        *
  18  *  License along with DMTCP:dmtcp/src.  If not, see                        *
  19  *  <http://www.gnu.org/licenses/>.                                         *
  20  ****************************************************************************/
  21 
  22 // msgrcv has confliciting return types on some systems (e.g. SLES 10)
  23 // So, we temporarily rename it so that type declarations are not for msgrcv.
  24 #define msgrcv msgrcv_glibc
  25 
  26 #include <sys/ipc.h>
  27 #include <sys/shm.h>
  28 #include <stdarg.h>
  29 
  30 #undef msgrcv
  31 
  32 #include "dmtcp.h"
  33 #include "sysvipc.h"
  34 #include "sysvipcwrappers.h"
  35 #include "jassert.h"
  36 
  37 using namespace dmtcp;
  38 
  39 static struct timespec ts_100ms = {0, 100 * 1000 * 1000};
  40 /******************************************************************************
  41  *
  42  * SysV Shm Methods
  43  *
  44  *****************************************************************************/
  45 
  46 extern "C"
  47 int shmget(key_t key, size_t size, int shmflg)
  48 {
  49   int realId = -1;
  50   int virtId = -1;
  51   DMTCP_PLUGIN_DISABLE_CKPT();
  52   realId = _real_shmget(key, size, shmflg);
  53   if (realId != -1) {
  54     SysVShm::instance().on_shmget(realId, key, size, shmflg);
  55     virtId = REAL_TO_VIRTUAL_SHM_ID(realId);
  56     JTRACE ("Creating new Shared memory segment")
  57       (key) (size) (shmflg) (realId) (virtId);
  58   }
  59   DMTCP_PLUGIN_ENABLE_CKPT();
  60   return virtId;
  61 }
  62 
  63 extern "C"
  64 void *shmat(int shmid, const void *shmaddr, int shmflg)
  65 {
  66   DMTCP_PLUGIN_DISABLE_CKPT();
  67   int realShmid = VIRTUAL_TO_REAL_SHM_ID(shmid);
  68   JASSERT(realShmid != -1) .Text("Not Implemented");
  69   void *ret = _real_shmat(realShmid, shmaddr, shmflg);
  70 #ifdef __arm__
  71   // This is arguably a bug in Linux kernel 2.6.28, 2.6.29, 3.0 - 3.2 and others
  72   // See:  https://bugs.kde.org/show_bug.cgi?id=222545
  73   //     On ARM, SHMLBA == 4*PAGE_SIZE instead of PAGESIZE
  74   //     So, this fails:
  75   //    shmaddr = shmat(shmid, NULL, 0); smdt(shmaddr); shmat(shmid, shaddr, 0);
  76   //       when shmaddr % 0x4000 != 0 (when shmaddr not multiple of SMLBA)
  77   // Workaround for bug in Linux kernel for ARM follows.
  78   // WHEN KERNEL FIX IS AVAILABLE, DO THIS ONLY FOR BUGGY KERNEL VERSIONS.
  79   if (((long)ret % 0x4000 != 0) && (ret != (void *)-1)) { // if ret%SHMLBA != 0
  80     void *ret_addr[20];
  81     unsigned int i;
  82     for (i = 0; i < sizeof(ret_addr) / sizeof(ret_addr[0]) ; i++) {
  83       ret_addr[i] = ret; // Save bad address for detaching later
  84       ret = _real_shmat(realShmid, shmaddr, shmflg); // Try again
  85       // if ret % SHMLBA == 0 { ... }
  86       if (((long)ret % 0x4000 == 0) || (ret == (void *)-1))
  87         break; // Good address (or error return)
  88     }
  89     // Detach all the bad addresses athat are not SHMLBA-aligned.
  90     if (i < sizeof(ret_addr) / sizeof(ret_addr[0]))
  91       for (unsigned int j = 0; j < i+1; j++)
  92         _real_shmdt( ret_addr[j] );
  93     JASSERT((long)ret % 0x4000 == 0)
  94       (shmaddr) (shmflg) (getpid())
  95       .Text ("Failed to get SHMLBA-aligned address after 20 tries");
  96   }
  97 #elif defined(__aarch64__)
  98 # warning "TODO: Implementation for ARM64."
  99 #endif
 100 
 101   if (ret != (void *) -1) {
 102     SysVShm::instance().on_shmat(shmid, shmaddr, shmflg, ret);
 103     JTRACE ("Mapping Shared memory segment") (shmid) (realShmid) (shmflg) (ret);
 104   }
 105   DMTCP_PLUGIN_ENABLE_CKPT();
 106   return ret;
 107 }
 108 
 109 extern "C"
 110 int shmdt(const void *shmaddr)
 111 {
 112   DMTCP_PLUGIN_DISABLE_CKPT();
 113   int ret = _real_shmdt(shmaddr);
 114   if (ret != -1) {
 115     SysVShm::instance().on_shmdt(shmaddr);
 116     JTRACE ("Unmapping Shared memory segment" ) (shmaddr);
 117   }
 118   DMTCP_PLUGIN_ENABLE_CKPT();
 119   return ret;
 120 }
 121 
 122 extern "C"
 123 int shmctl(int shmid, int cmd, struct shmid_ds *buf)
 124 {
 125   DMTCP_PLUGIN_DISABLE_CKPT();
 126   int realShmid = VIRTUAL_TO_REAL_SHM_ID(shmid);
 127   JASSERT(realShmid != -1);
 128   int ret = _real_shmctl(realShmid, cmd, buf);
 129   DMTCP_PLUGIN_ENABLE_CKPT();
 130   return ret;
 131 }
 132 
 133 /******************************************************************************
 134  *
 135  * SysV Semaphore Methods
 136  *
 137  *****************************************************************************/
 138 
 139 extern "C"
 140 int semget(key_t key, int nsems, int semflg)
 141 {
 142   int realId = -1;
 143   int virtId = -1;
 144   DMTCP_PLUGIN_DISABLE_CKPT();
 145   realId = _real_semget (key, nsems, semflg);
 146   if (realId != -1) {
 147     SysVSem::instance().on_semget(realId, key, nsems, semflg);
 148     virtId = REAL_TO_VIRTUAL_SEM_ID(realId);
 149     JTRACE ("Creating new SysV Semaphore" ) (key) (nsems) (semflg);
 150   }
 151   DMTCP_PLUGIN_ENABLE_CKPT();
 152   return virtId;
 153 }
 154 
 155 extern "C"
 156 int semop(int semid, struct sembuf *sops, size_t nsops)
 157 {
 158   return semtimedop(semid, sops, nsops, NULL);
 159 }
 160 
 161 extern "C"
 162 int semtimedop(int semid, struct sembuf *sops, size_t nsops,
 163                const struct timespec *timeout)
 164 {
 165   struct timespec totaltime = {0, 0};
 166   int ret;
 167   int realId;
 168   bool ipc_nowait_specified = false;
 169 
 170   for (size_t i = 0; i < nsops; i++) {
 171     if (sops[i].sem_flg & IPC_NOWAIT) {
 172       ipc_nowait_specified = true;
 173       break;
 174     }
 175   }
 176 
 177   if (ipc_nowait_specified ||
 178       (timeout != NULL && TIMESPEC_CMP(timeout, &ts_100ms, <))) {
 179     DMTCP_PLUGIN_DISABLE_CKPT();
 180     realId = VIRTUAL_TO_REAL_SEM_ID(semid);
 181     JASSERT(realId != -1);
 182     ret = _real_semtimedop(realId, sops, nsops, timeout);
 183     if (ret == 0) {
 184       SysVSem::instance().on_semop(semid, sops, nsops);
 185     }
 186     DMTCP_PLUGIN_ENABLE_CKPT();
 187     return ret;
 188   }
 189 
 190   /*
 191    * We continue to call pthread_tryjoin_np (and sleep) until we have gone past
 192    * the abstime provided by the caller
 193    */
 194   while (timeout == NULL || TIMESPEC_CMP(&totaltime, timeout, <)) {
 195     ret = EAGAIN;
 196     DMTCP_PLUGIN_DISABLE_CKPT();
 197     realId = VIRTUAL_TO_REAL_SEM_ID(semid);
 198     JASSERT(realId != -1);
 199     ret = _real_semtimedop(realId, sops, nsops, &ts_100ms);
 200     if (ret == 0) {
 201       SysVSem::instance().on_semop(semid, sops, nsops);
 202     }
 203     DMTCP_PLUGIN_ENABLE_CKPT();
 204 
 205     // TODO Handle EIDRM
 206     if (ret == 0 ||
 207         (ret == -1 && errno != EAGAIN)) {
 208       return ret;
 209     }
 210 
 211     TIMESPEC_ADD(&totaltime, &ts_100ms, &totaltime);
 212   }
 213   errno = EAGAIN;
 214   return -1;
 215 }
 216 
 217 extern "C"
 218 int semctl(int semid, int semnum, int cmd, ...)
 219 {
 220   union semun uarg;
 221   va_list arg;
 222   va_start (arg, cmd);
 223   uarg = va_arg (arg, union semun);
 224   va_end (arg);
 225 
 226   DMTCP_PLUGIN_DISABLE_CKPT();
 227   int realId = VIRTUAL_TO_REAL_SEM_ID(semid);
 228   JASSERT(realId != -1);
 229   int ret = _real_semctl(realId, semnum, cmd, uarg);
 230   if (ret != -1) {
 231     SysVSem::instance().on_semctl(semid, semnum, cmd, uarg);
 232   }
 233   DMTCP_PLUGIN_ENABLE_CKPT();
 234   return ret;
 235 }
 236 /******************************************************************************
 237  *
 238  * SysV Msg Queue Methods
 239  *
 240  *****************************************************************************/
 241 
 242 extern "C"
 243 int msgget(key_t key, int msgflg)
 244 {
 245   int realId = -1;
 246   int virtId = -1;
 247   DMTCP_PLUGIN_DISABLE_CKPT();
 248   realId = _real_msgget (key, msgflg);
 249   if (realId != -1) {
 250     SysVMsq::instance().on_msgget(realId, key, msgflg);
 251     virtId = REAL_TO_VIRTUAL_MSQ_ID(realId);
 252     JTRACE ("Creating new SysV Msg Queue" ) (key) (msgflg);
 253   }
 254   DMTCP_PLUGIN_ENABLE_CKPT();
 255   return virtId;
 256 }
 257 
 258 extern "C"
 259 int msgsnd(int msqid, const void *msgp, size_t msgsz, int msgflg)
 260 {
 261   int ret;
 262   int realId;
 263 
 264   /*
 265    * We continue to call msgsnd with IPC_NOWAIT (and sleep) until we succeed
 266    * or fail with something other than EAGAIN
 267    * If IPC_NOWAIT was specified and msgsnd fails with EAGAIN, return.
 268    */
 269   while (true) {
 270     DMTCP_PLUGIN_DISABLE_CKPT();
 271     realId = VIRTUAL_TO_REAL_MSQ_ID(msqid);
 272     JASSERT(realId != -1);
 273     ret = _real_msgsnd(realId, msgp, msgsz, msgflg | IPC_NOWAIT);
 274     if (ret == 0) {
 275       SysVMsq::instance().on_msgsnd(msqid, msgp, msgsz, msgflg);
 276     }
 277     DMTCP_PLUGIN_ENABLE_CKPT();
 278 
 279     // TODO Handle EIDRM
 280     if ((ret == 0) ||
 281         (ret == -1 && errno != EAGAIN) ||
 282         (msgflg & IPC_NOWAIT)) {
 283       return ret;
 284     }
 285 
 286     nanosleep(&ts_100ms, NULL);
 287   }
 288   JASSERT(false) .Text("Not Reached");
 289   return -1;
 290 }
 291 
 292 extern "C"
 293 ssize_t msgrcv(int msqid, void *msgp, size_t msgsz, long msgtyp, int msgflg)
 294 {
 295   int ret;
 296   int realId;
 297 
 298   /*
 299    * We continue to call msgrcv with IPC_NOWAIT (and sleep) until we succeed
 300    * or fail with something other than EAGAIN
 301    * If IPC_NOWAIT was specified and msgsnd fails with EAGAIN, return.
 302    */
 303   while (true) {
 304     DMTCP_PLUGIN_DISABLE_CKPT();
 305     realId = VIRTUAL_TO_REAL_MSQ_ID(msqid);
 306     JASSERT(realId != -1);
 307     ret = _real_msgrcv(realId, msgp, msgsz, msgtyp, msgflg | IPC_NOWAIT);
 308     if (ret == 0) {
 309       SysVMsq::instance().on_msgrcv(msqid, msgp, msgsz, msgtyp, msgflg);
 310     }
 311     DMTCP_PLUGIN_ENABLE_CKPT();
 312 
 313     // TODO Handle EIDRM
 314     if ((ret >= 0) ||
 315         (ret == -1 && errno != ENOMSG) ||
 316         (msgflg & IPC_NOWAIT)) {
 317       return ret;
 318     }
 319 
 320     nanosleep(&ts_100ms, NULL);
 321   }
 322   JASSERT(false) .Text("Not Reached");
 323   return -1;
 324 }
 325 
 326 
 327 extern "C"
 328 int msgctl(int msqid, int cmd, struct msqid_ds *buf)
 329 {
 330   DMTCP_PLUGIN_DISABLE_CKPT();
 331   int realId = VIRTUAL_TO_REAL_MSQ_ID(msqid);
 332   JASSERT(realId != -1);
 333   int ret = _real_msgctl(realId, cmd, buf);
 334   if (ret != -1) {
 335     SysVMsq::instance().on_msgctl(msqid, cmd, buf);
 336   }
 337   DMTCP_PLUGIN_ENABLE_CKPT();
 338   return ret;
 339 }

/* [<][>][^][v][top][bottom][index][help] */