Пример #1
0
unsigned int LBSM_Shmem_Update(HEAP heap, int/*bool*/ wait)
{
    size_t heapsize = HEAP_Size(heap);
    void*  heapbase = HEAP_Base(heap);
    unsigned int updated = 0;
    int i;

    assert(heapbase  &&  heapsize);
    for (i = 0;  i < 2;  i++) {
        int can_wait = wait ||  (s_ShmemSize[i]  &&  (!i  ||  updated));
        if (!s_Shmem_WLock(i, can_wait))
            continue;

        /* Update shmem here: strict checks for the first time */
        if (s_ShmemSize[i] != heapsize) {
            int   shmid;
            void* shmem;
            s_Shmem_Destroy(i, s_ShmemSize[i] ? 0 : getpid());
            if ((shmid = shmget(k_ShmemKey[i], heapsize,
                                LBSM_SHM_PROT | IPC_CREAT | IPC_EXCL)) < 0  ||
                !(shmem = shmat(shmid, 0, 0))  ||  shmem == (void*)(-1)) {
                CORE_LOGF_ERRNO_X(22, eLOG_Error, errno,
                                  ("Unable to re-create LBSM shmem[%d]",
                                   i + 1));
                s_Shmem_WUnlock(i);
                return 0/*update failed*/;
            }
            s_Shmid[i] = shmid;
            s_Shmem[i] = shmem;
            s_ShmemSize[i] = heapsize;
        }
        memcpy(s_Shmem[i], heapbase, heapsize);
        if (!s_Shmem_WUnlock(i)) {
            CORE_LOGF_ERRNO_X(23, eLOG_Warning, errno,
                              ("Update failed to unlock shmem[%d]", i + 1));
        }
        updated |= 1 << i;
    }
    return updated;
}
Пример #2
0
static void s_Shmem_Destroy(int which, pid_t own_pid)
{
    if (s_Shmid[which] < 0) {
        assert(!s_Shmem[which]  &&  !s_ShmemSize[which]);
        return;
    }
    if (s_Shmem[which]) {
        if (shmdt(s_Shmem[which]) < 0) {
            CORE_LOGF_ERRNO_X(14, eLOG_Error, errno,
                              ("Unable to detach LBSM shmem[%d]", which + 1));
        }
        s_Shmem[which] = 0;
    }
    if (own_pid) {
        struct shmid_ds shm_ds;
        if (shmctl(s_Shmid[which], IPC_STAT, &shm_ds) < 0)
            shm_ds.shm_cpid = 0;
        if (shm_ds.shm_cpid != own_pid) {
            if (shm_ds.shm_cpid) {
                CORE_LOGF_X(15, eLOG_Error,
                            ("Not an owner (%lu) to remove LBSM shmem[%d]",
                             (long) shm_ds.shm_cpid, which + 1));
            } else {
                CORE_LOGF_ERRNO(eLOG_Error, errno,
                                ("Unable to stat LBSM shmem[%d]", which + 1));
            }
            own_pid = 0;
        }
    } else
        own_pid = 1;
    if (own_pid  &&  shmctl(s_Shmid[which], IPC_RMID, 0) < 0) {
        CORE_LOGF_ERRNO_X(16, eLOG_Error, errno,
                          ("Unable to remove LBSM shmem[%d]", which + 1));
    }
    s_Shmid[which]     = -1;
    s_ShmemSize[which] =  0;
}
Пример #3
0
HEAP LBSM_Shmem_Attach(void)
{
    int  fallback = 0; /*FIXME: to become a parameter*/
    int  which;
    HEAP heap;

#ifdef LBSM_DEBUG
    CORE_LOG(eLOG_Trace, "LBSM ATTACHING%s", fallback ? " (fallback)" : "");
#endif /*LBSM_DEBUG*/
    if ((which = s_Shmem_RLock(!fallback)) < 0) {
        CORE_LOG_ERRNO_X(10, eLOG_Warning, errno,
                         "Cannot lock LBSM shmem to attach");
        return 0;
    }
#ifdef LBSM_DEBUG
    CORE_LOGF(eLOG_Trace, ("LBSM R-lock[%d] acquired", which + 1));
#endif /*LBSM_DEBUG*/
    if (!(heap = s_Shmem_Attach(which))) {
        int/*bool*/ attached = s_Shmem[which] != 0 ? 1/*true*/ : 0/*false*/;
        s_Shmem_RUnlock(which);
        CORE_LOGF_ERRNO_X(11, eLOG_Error, errno,
                          ("Cannot %s LBSM shmem[%d]",
                           attached ? "access" : "attach", which + 1));
    }
#ifdef LBSM_DEBUG
    else {
        CORE_LOGF(eLOG_Trace,
                  ("LBSM heap[%p, %p, %d] attached",
                   heap, HEAP_Base(heap), which + 1));
        assert(HEAP_Serial(heap) == which + 1);
    }
#endif /*LBSM_DEBUG*/
    if (s_Shmem[which = !which]) {
#ifdef LBSM_DEBUG
        CORE_LOGF(eLOG_Trace, ("LBSM shmem[%d] detached", which + 1));
#endif /*LBSM_DEBUG*/
        shmdt(s_Shmem[which]);
        s_Shmem[which] =  0;
        s_Shmid[which] = -1;
    } else
        assert(s_Shmid[which] < 0);
    s_ShmemSize[which] =  0;
    return heap;
}
Пример #4
0
/* Return non-zero if successful;  return zero on failure (no lock acquired).
 * If "wait" passed greater than zero do not attempt to assassinate a contender
 * (try to identify and print its PID anyways).  Otherwise, having killed
 * the contender, try to re-acquire the lock (without.
 */
static int/*bool*/ s_Shmem_WLock(int which, int/*bool*/ wait)
{
    static union semun dummy;
    int locked;
    int pid;

#ifdef LBSM_DEBUG
    CORE_LOGF(eLOG_Trace,
              ("LBSM W-lock[%d] acquire%s", which + 1, wait ? " w/wait" : ""));
#endif /*LBSM_DEBUG*/

    if ((locked = s_Shmem_TryWLock(which)) == 0)
        return 1/*success*/;

    if (locked < 0) {
        /* even [1] was not successfully locked, so we have either
         *   a/ a hanging writer, or
         *   b/ a hanging old reader (which doesn't change [2] in block 0 only)
         * In either case, we can try to obtain a PID of the offender.
         */
        if ((pid = semctl(s_Muxid, (which << 1) | 1, GETPID, dummy)) > 0) {
            int self   = (pid_t) pid == getpid();
            int other  = !self  &&  (kill(pid, 0) == 0  ||  errno == EPERM);
            int killed = 0;
            if (!wait) {
                if (other  &&  kill(pid, SIGTERM) == 0) {
                    CORE_LOGF_X(17, eLOG_Warning,
                                ("Terminating PID %lu", (long) pid));
                    sleep(1); /* let them catch SIGTERM and exit gracefully */
                    kill(pid, SIGKILL);
                    killed = 1;
                } else {
                    CORE_LOGF_X(18, eLOG_Warning,
                                ("Unable to kill PID %lu", (long) pid));
                }
            }
            CORE_LOGF_X(19, eLOG_Warning,
                        ("LBSM lock[%d] %s revoked from PID %lu (%s)",
                         which + 1, killed ? "is being" : "has to be",
                         (long) pid, self  ? "self" :
                         other ? (killed ? "killed" : "hanging") : "zombie"));
        } else if (pid < 0)
            return 0/*severe failure: most likely removed IPC id*/;
    } else {
        pid = 0;
        /* [1] was free (now locked) but [2] was taken by someone else,
         * we have a hanging reader, no additional info is available.
         */
        if (!wait) {
            union semun arg;
            arg.val = 1;
            if (semctl(s_Muxid, (which << 1) + 2, SETVAL, arg) < 0) {
                CORE_LOGF_ERRNO_X(9, eLOG_Error, errno,
                                  ("Unable to adjust LBSM access count[%d]",
                                   which + 1));
            }
            wait = 1/*this makes us undo [1] and fail*/;
        }
        if (wait) {
            int x_errno = errno;
            s_Shmem_Unlock(which, 1);
            errno = x_errno;
        }
    }

    if (!pid) {
        int val;
        if ((val = semctl(s_Muxid, (which << 1) + 2, GETVAL, dummy)) > 1) {
            CORE_LOGF_X(20, eLOG_Warning,
                        ("%u hanging readers in LBSM shmem[%d]%s",
                         (unsigned int) val, which + 1, wait ? "" :
                         locked < 0 ? ", revoking lock" : ", lock revoked"));
        } else {
            CORE_LOGF_X(21, eLOG_Warning,
                        ("A hanging reader in LBSM shmem[%d]%s",
                         which + 1, wait ? "" :
                         locked < 0 ? ", revoking lock" : ", lock revoked"));
        }
    }

    if (wait)
        return 0/*failure*/;

    if (locked > 0)
        return 1/*success: good to go*/;

#ifdef LBSM_DEBUG
    CORE_LOGF(eLOG_Trace,
              ("LBSM W-lock[%d] re-acquire", which + 1));
#endif /*LBSM_DEBUG*/
    return s_Shmem_WLock(which, 0/*no wait*/);
}
Пример #5
0
static HEAP s_GetHeapCopy(TNCBI_Time now)
{
    enum {
        eNone     = 0,
        eAgain    = 1,
        eFallback = 2
    } retry   = eNone;
    HEAP heap = 0;
    HEAP lbsm;

    for (;;) {
        const SLBSM_Version *c, *v;
        int serial = 0;

        CORE_LOCK_WRITE;

        if (s_Heap) {
            c = LBSM_GetVersion(s_Heap);
            assert(c  &&  c->major == LBSM_HEAP_VERSION_MAJ);
            assert((void*) c == (void*) HEAP_Base(s_Heap));
            if (c->entry.good < now) {
#ifdef LBSM_DEBUG
                CORE_LOGF(eLOG_Trace,
                          ("Cached LBSM heap[%p, %p, %d] expired, dropped",
                           s_Heap, HEAP_Base(s_Heap), HEAP_Serial(s_Heap)));
#endif /*LBSM_DEBUG*/
                HEAP_Destroy(s_Heap);
                s_Heap = 0;
            }
#ifdef LBSM_DEBUG
            else {
                CORE_LOGF(eLOG_Trace,
                          ("Cached LBSM heap[%p, %p, %d] valid",
                           s_Heap, HEAP_Base(s_Heap), HEAP_Serial(s_Heap)));
            }
#endif /*LBSM_DEBUG*/
        } else
            c = 0/*dummy for compiler not to complain*/;
        
        if (!(lbsm = LBSM_Shmem_Attach(retry == eFallback))
            ||  (serial = HEAP_Serial(lbsm)) <= 0) {
            if (lbsm) {
                CORE_LOGF_X(1, eLOG_Error,
                            ("Bad serial (%d) from LBSM heap attach", serial));
            } /* else, an error has already been posted */
            break;
        }

        if (!(v = LBSM_GetVersion(lbsm))
            ||  (v->major < LBSM_HEAP_VERSION_MAJ
                 ||  (v->major == LBSM_HEAP_VERSION_MAJ
                      &&  v->minor < LBSM_HEAP_VERSION_MIN))) {
            if (v) {
                CORE_LOGF_X(2, eLOG_Error,
                            ("LBSM heap[%d] version mismatch"
                             " (current=%hu.%hu, expected=%u.%u+)",
                             serial, v->major, v->minor,
                             LBSM_HEAP_VERSION_MAJ, LBSM_HEAP_VERSION_MIN));
            } else {
                CORE_LOGF_X(3, eLOG_Error,
                            ("LBSM heap[%d] has no version", serial));
            }
            break;
        }

        if (v->entry.good < now) {
            CORE_LOGF_X(4, eLOG_Warning,
                        ("LBSM heap[%d] is out-of-date"
                         " (current=%lu, expiry=%lu, delta=%lu)%s", serial,
                         (unsigned long) now, (unsigned long) v->entry.good,
                         (unsigned long) now -(unsigned long) v->entry.good,
                         !retry  &&  serial > 1 ? ", re-trying" : ""));
            if (!retry  &&   serial > 1) {
                LBSM_Shmem_Detach(heap);
                retry = eFallback;
                CORE_UNLOCK;
                continue;
            }
            if (s_Heap) {
#ifdef LBSM_DEBUG
                CORE_LOGF(eLOG_Trace,
                          ("Cached LBSM heap[%p, %p, %d] dropped",
                           s_Heap, HEAP_Base(s_Heap), HEAP_Serial(s_Heap)));
#endif /*LBSM_DEBUG*/
                HEAP_Destroy(s_Heap);
                s_Heap = 0;
            }
            break;
        }
        assert((void*) v == (void*) HEAP_Base(lbsm));

        if (s_Heap) {
            if (c->count == v->count  &&  c->cksum == v->cksum) {
#ifdef LBSM_DEBUG
                CORE_LOGF(eLOG_Trace,
                          ("Cached LBSM heap[%p, %p, %d] used",
                           s_Heap, HEAP_Base(s_Heap), HEAP_Serial(s_Heap)));
#endif /*LBSM_DEBUG*/
                heap = s_Heap;
                break;
            }
#ifdef LBSM_DEBUG
            CORE_LOGF(eLOG_Trace,
                      ("Cached LBSM heap[%p, %p, %d] is stale, dropped",
                       s_Heap, HEAP_Base(s_Heap), HEAP_Serial(s_Heap)));
#endif /*LBSM_DEBUG*/
            HEAP_Destroy(s_Heap);
            s_Heap = 0;
        }

        if (!(heap = HEAP_Copy(lbsm, 0, -serial))) {
            CORE_LOGF_ERRNO_X(6, eLOG_Error, errno,
                              ("Unable to copy LBSM heap[%d]", serial));
            break;
        }

        if (s_VerifyChecksum(heap, v->cksum)) {
#ifdef LBSM_DEBUG
            CORE_LOGF(eLOG_Trace,
                      ("Cached LBSM heap[%p, %p, %d] renewed",
                       heap, HEAP_Base(heap), HEAP_Serial(heap)));
#endif /*LBSM_DEBUG*/
            s_Heap = heap;
            break;
        }

        CORE_LOGF_X(7, retry ? eLOG_Error : eLOG_Warning,
                    ("LBSM heap[%p, %p, %d]%s checksum failure%s",
                     (void*) heap, HEAP_Base(heap), HEAP_Serial(heap),
                     retry == eAgain ? " persistent" : "",
                     retry           ? ""            : ", re-trying"));

        verify(HEAP_Destroy(heap) == 0);
        heap = 0;
        if (retry)
            break;

        LBSM_Shmem_Detach(lbsm);
        retry = eAgain;
        CORE_UNLOCK;
    }

    assert(!heap  ||  heap != lbsm);
    if (heap  &&  heap == s_Heap)
        verify(HEAP_AddRef(s_Heap) > 1);

    LBSM_Shmem_Detach(lbsm);
    CORE_UNLOCK;
    return heap;
}