Changeset 1366 in svn for trunk/xcache/xc_mutex.c


Ignore:
Timestamp:
2013-09-09T18:16:05+02:00 (23 months ago)
Author:
Xuefer
Message:

fixes #323: refix locking impl for threaded env

File:
1 moved

Legend:

Unmodified
Added
Removed
  • trunk/xcache/xc_mutex.c

    r1365 r1366  
    1 #include "xc_lock.h"
     1#include "xc_mutex.h"
    22#include "xcache.h"
    33#include <stdio.h>
     
    1212#endif
    1313
    14 /* {{{ detect what type of lock is needed */
     14/* {{{ detect what type of mutex is needed */
    1515#ifdef ZTS
    16 #   define XC_LOCK_NEED_TS
    17 #endif
    18 
    19 #ifndef ZEND_WIN32
    20 #   define XC_LOCK_NEED_INTERPROCESS
    21 #endif
    22 
    23 #if defined(XC_LOCK_NEED_TS) && defined(XC_LOCK_NEED_INTERPROCESS)
    24 /* allow switching off interprocess support */
    25 #   define XC_LOCK_HAVE_INTERPROCESS_SWITCH
    26 #endif
    27 /* }}} */
    28 
    29 /* {{{ detect which lock is needed */
    30 #if defined(XC_LOCK_NEED_TS) && defined(XC_LOCK_NEED_INTERPROCESS)
     16#   define XC_MUTEX_NEED_TS
     17#endif
     18
     19#ifdef HAVE_FORK
     20#   define XC_MUTEX_NEED_INTERPROCESS
     21#endif
     22
     23#if defined(XC_MUTEX_NEED_TS) && defined(XC_MUTEX_NEED_INTERPROCESS)
     24/* the check is not even needed for non-threaded env */
     25#   define XC_MUTEX_HAVE_INTERPROCESS_SWITCH
     26#endif
     27/* }}} */
     28
     29/* {{{ detect which mutex is needed */
     30#if defined(XC_MUTEX_NEED_TS) && defined(XC_MUTEX_NEED_INTERPROCESS)
    3131#   ifdef PTHREADS
    32 #       define XC_LOCK_USE_PTHREAD
     32#       define XC_MUTEX_USE_PTHREAD
    3333#       ifndef _POSIX_THREAD_PROCESS_SHARED
    34 #           define XC_LOCK_USE_FCNTL
     34#           define XC_MUTEX_USE_FCNTL
    3535#       endif
    3636#   else
    37 #       define XC_LOCK_USE_TSRM
    38 #       define XC_LOCK_USE_FCNTL
     37#       define XC_MUTEX_USE_TSRM
     38#       define XC_MUTEX_USE_FCNTL
    3939#   endif
    40 #elif defined(XC_LOCK_NEED_TS)
    41 #   define XC_LOCK_USE_TSRM
    42 #elif defined(XC_LOCK_NEED_INTERPROCESS)
    43 #   define XC_LOCK_USE_FCNTL
    44 #else
    45 #   define XC_LOCK_USE_NOOP
    46 #endif
    47 /* }}} */
    48 
    49 /* {{{ fcntl lock impl */
    50 #ifdef XC_LOCK_USE_FCNTL
     40#elif defined(XC_MUTEX_NEED_TS)
     41#   define XC_MUTEX_USE_TSRM
     42#elif defined(XC_MUTEX_NEED_INTERPROCESS)
     43#   define XC_MUTEX_USE_FCNTL
     44#else
     45#   define XC_MUTEX_USE_NOOP
     46#endif
     47/* }}} */
     48
     49/* {{{ fcntl mutex impl */
     50#ifdef XC_MUTEX_USE_FCNTL
    5151#ifndef ZEND_WIN32
    5252typedef int HANDLE;
     
    7171    char *pathname;
    7272#endif
    73 } xc_fcntl_lock_t;
     73} xc_fcntl_mutex_t;
    7474
    7575#ifndef ZEND_WIN32
     
    7878#   define LCK_UN F_UNLCK
    7979#   define LCK_NB 0
    80 static inline int dolock(xc_fcntl_lock_t *lck, int type)
     80static inline int dolock(xc_fcntl_mutex_t *fcntl_mutex, int type)
    8181{
    8282    int ret;
     
    9090
    9191    do {
    92         ret = fcntl(lck->fd, F_SETLKW, &lock);
     92        ret = fcntl(fcntl_mutex->fd, F_SETLKW, &lock);
    9393    } while (ret < 0 && errno == EINTR);
    9494    return ret;
     
    108108#   define LCK_UN 0
    109109#   define LCK_NB LOCKFILE_FAIL_IMMEDIATELY
    110 static inline int dolock(xc_fcntl_lock_t *lck, int type)
     110static inline int dolock(xc_fcntl_mutex_t *fcntl_mutex, int type)
    111111{
    112112    static OVERLAPPED offset = {0, 0, 0, 0, NULL};
    113113
    114114    if (type == LCK_UN) {
    115         return UnlockFileEx(lck->fd, 0, 1, 0, &offset);
     115        return UnlockFileEx(fcntl_mutex->fd, 0, 1, 0, &offset);
    116116    }
    117117    else {
    118         return LockFileEx(lck->fd, type, 0, 1, 0, &offset);
    119     }
    120 }
    121 #endif
    122 /* }}} */
    123 
    124 static zend_bool xc_fcntl_init(xc_fcntl_lock_t *lck, const char *pathname) /* {{{ */
     118        return LockFileEx(fcntl_mutex->fd, type, 0, 1, 0, &offset);
     119    }
     120}
     121#endif
     122/* }}} */
     123
     124static zend_bool xc_fcntl_init(xc_fcntl_mutex_t *fcntl_mutex, const char *pathname) /* {{{ */
    125125{
    126126    HANDLE fd;
     
    140140            }
    141141        }
    142         size = strlen(tmpdir) + sizeof("/.xcache.lock") - 1 + 3 * 10 + 100;
     142        size = strlen(tmpdir) + sizeof("/.xcache.mutex") - 1 + 3 * 10 + 100;
    143143        myname = malloc(size);
    144         snprintf(myname, size - 1, "%s%c.xcache.%d.%d.%d.lock", tmpdir, DEFAULT_SLASH, (int) getuid(), (int) getpid(), ++instanceId);
     144        snprintf(myname, size - 1, "%s%c.xcache.%d.%d.%d.mutex", tmpdir, DEFAULT_SLASH, (int) getuid(), (int) getpid(), ++instanceId);
    145145        pathname = myname;
    146146    }
     
    152152
    153153    if (fd != INVALID_HANDLE_VALUE) {
    154         lck->fd = fd;
     154        fcntl_mutex->fd = fd;
    155155#ifdef __CYGWIN__
    156156        size = strlen(pathname) + 1;
    157         lck->pathname = malloc(size);
    158         memcpy(lck->pathname, pathname, size);
     157        fcntl_mutex->pathname = malloc(size);
     158        memcpy(fcntl_mutex->pathname, pathname, size);
    159159#else
    160160        unlink(pathname);
     
    163163    else {
    164164        zend_error(E_ERROR, "xc_fcntl_create: open(%s, O_RDWR|O_CREAT, 0666) failed:", pathname);
    165         lck = NULL;
     165        fcntl_mutex = NULL;
    166166    }
    167167
     
    170170    }
    171171
    172     return lck ? 1 : 0;
    173 }
    174 /* }}} */
    175 static void xc_fcntl_destroy(xc_fcntl_lock_t *lck) /* {{{ */
    176 {
    177     close(lck->fd);
     172    return fcntl_mutex ? 1 : 0;
     173}
     174/* }}} */
     175static void xc_fcntl_destroy(xc_fcntl_mutex_t *fcntl_mutex) /* {{{ */
     176{
     177    close(fcntl_mutex->fd);
    178178#ifdef __CYGWIN__
    179     unlink(lck->pathname);
    180     free(lck->pathname);
    181 #endif
    182 }
    183 /* }}} */
    184 static void xc_fcntl_lock(xc_fcntl_lock_t *lck) /* {{{ */
    185 {
    186     if (dolock(lck, LCK_WR) < 0) {
    187         zend_error(E_ERROR, "xc_fcntl_lock failed errno:%d", errno);
    188     }
    189 }
    190 /* }}} */
    191 static void xc_fcntl_rdlock(xc_fcntl_lock_t *lck) /* {{{ */
    192 {
    193     if (dolock(lck, LCK_RD) < 0) {
    194         zend_error(E_ERROR, "xc_fcntl_lock failed errno:%d", errno);
    195     }
    196 }
    197 /* }}} */
    198 static void xc_fcntl_unlock(xc_fcntl_lock_t *lck) /* {{{ */
    199 {
    200     if (dolock(lck, LCK_UN) < 0) {
     179    unlink(fcntl_mutex->pathname);
     180    free(fcntl_mutex->pathname);
     181#endif
     182}
     183/* }}} */
     184static void xc_fcntl_mutex(xc_fcntl_mutex_t *fcntl_mutex) /* {{{ */
     185{
     186    if (dolock(fcntl_mutex, LCK_WR) < 0) {
     187        zend_error(E_ERROR, "xc_fcntl_mutex failed errno:%d", errno);
     188    }
     189}
     190/* }}} */
     191static void xc_fcntl_rdlock(xc_fcntl_mutex_t *fcntl_mutex) /* {{{ */
     192{
     193    if (dolock(fcntl_mutex, LCK_RD) < 0) {
     194        zend_error(E_ERROR, "xc_fcntl_mutex failed errno:%d", errno);
     195    }
     196}
     197/* }}} */
     198static void xc_fcntl_unlock(xc_fcntl_mutex_t *fcntl_mutex) /* {{{ */
     199{
     200    if (dolock(fcntl_mutex, LCK_UN) < 0) {
    201201        zend_error(E_ERROR, "xc_fcntl_unlock failed errno:%d", errno);
    202202    }
    203203}
    204204/* }}} */
    205 #endif /* XC_LOCK_USE_FCNTL */
    206 
    207 struct _xc_lock_t {
    208 #ifdef XC_LOCK_USE_NOOP
     205#endif /* XC_MUTEX_USE_FCNTL */
     206
     207struct _xc_mutex_t {
     208#ifdef XC_MUTEX_USE_NOOP
    209209    int dummy;
    210210#endif
    211211
    212 #ifdef XC_LOCK_USE_TSRM
     212#ifdef XC_MUTEX_HAVE_INTERPROCESS_SWITCH
     213    zend_bool want_inter_process;  /* whether the lock is created for inter process usage */
     214#endif
     215    zend_bool shared; /* shared, or locally allocated */
     216
     217#ifdef XC_MUTEX_USE_TSRM
    213218    MUTEX_T tsrm_mutex;
    214219#endif
    215220
    216 #ifdef XC_LOCK_HAVE_INTERPROCESS_SWITCH
    217     zend_bool interprocess;
    218 #endif
    219 
    220 #ifdef XC_LOCK_USE_PTHREAD
     221#ifdef XC_MUTEX_USE_PTHREAD
    221222    pthread_mutex_t pthread_mutex;
    222223#endif
    223224
    224 #ifdef XC_LOCK_USE_FCNTL
    225     xc_fcntl_lock_t fcntl_lock;
     225#ifdef XC_MUTEX_USE_FCNTL
     226    xc_fcntl_mutex_t fcntl_mutex;
    226227#endif
    227228
     
    231232};
    232233
    233 #ifdef XC_LOCK_HAVE_INTERPROCESS_SWITCH
    234 #   define XC_LOCK_INTERPROCESS (lck->interprocess)
    235 #else
    236 #   define XC_LOCK_INTERPROCESS 1
    237 #endif
    238 
    239 size_t xc_lock_size(void) /* {{{ */
    240 {
    241     return sizeof(xc_lock_t);
    242 }
    243 /* }}} */
    244 xc_lock_t *xc_lock_init(xc_lock_t *lck, const char *pathname, unsigned char interprocess) /* {{{ */
    245 {
    246 #ifdef XC_LOCK_HAVE_INTERPROCESS_SWITCH
    247     lck->interprocess = interprocess;
    248 #endif
    249 
    250 #ifdef XC_LOCK_USE_PTHREAD
     234#ifdef XC_MUTEX_HAVE_INTERPROCESS_SWITCH
     235#   define xc_want_inter_process() (mutex->want_inter_process)
     236#elif defined(HAVE_FORK)
     237#   define xc_want_inter_process() 1
     238#else
     239#   define xc_want_inter_process() 0
     240#endif
     241
     242size_t xc_mutex_size(void) /* {{{ */
     243{
     244    return sizeof(xc_mutex_t);
     245}
     246/* }}} */
     247xc_mutex_t *xc_mutex_init(xc_mutex_t *const shared_mutex, const char *pathname, unsigned char want_inter_process) /* {{{ */
     248{
     249    xc_mutex_t *mutex = NULL;
     250
     251#ifndef HAVE_FORK
     252    want_inter_process = 0;
     253#endif
     254
     255    /* if interprocessed is needed, shared_mutex is required to be a pre-allocated memory on shm
     256     * this function can always return non-shared memory if necessary despite shared memory is given
     257     */
     258
     259    /* when inter-process is wanted, pthread lives in shm */
     260#ifdef XC_MUTEX_USE_PTHREAD
     261    if (want_inter_process) {
     262        assert(shared_mutex);
     263        mutex = shared_mutex;
     264        mutex->shared = 1;
     265    }
     266    else
     267#endif
    251268    {
     269        /* all other mutex assumed live locally */
     270        mutex = calloc(1, sizeof(*mutex));
     271        mutex->shared = 0;
     272#ifdef XC_MUTEX_HAVE_INTERPROCESS_SWITCH
     273        mutex->want_inter_process = want_inter_process;
     274#endif
     275    }
     276
     277
     278#ifdef XC_MUTEX_USE_PTHREAD
     279    {
     280        /* If you see mutex leak using valgrind, see xc_mutex_destroy function */
    252281        pthread_mutexattr_t psharedm;
    253282        pthread_mutexattr_init(&psharedm);
    254         pthread_mutexattr_setpshared(&psharedm, XC_LOCK_INTERPROCESS ? PTHREAD_PROCESS_PRIVATE : PTHREAD_PROCESS_SHARED);
    255         pthread_mutex_init(&lck->pthread_mutex, &psharedm);
    256     }
    257 #endif
    258 
    259 #ifdef XC_LOCK_USE_TSRM
    260     lck->tsrm_mutex = tsrm_mutex_alloc();
    261 #endif
    262 
    263 #ifdef XC_LOCK_USE_FCNTL
    264     if (XC_LOCK_INTERPROCESS) {
    265         xc_fcntl_init(&lck->fcntl_lock, pathname);
     283        pthread_mutexattr_setpshared(&psharedm, xc_want_inter_process() ? PTHREAD_PROCESS_PRIVATE : PTHREAD_PROCESS_SHARED);
     284        pthread_mutex_init(&mutex->pthread_mutex, &psharedm);
     285    }
     286#endif
     287
     288#ifdef XC_MUTEX_USE_TSRM
     289    mutex->tsrm_mutex = tsrm_mutex_alloc();
     290#endif
     291
     292#ifdef XC_MUTEX_USE_FCNTL
     293    if (xc_want_inter_process()) {
     294        xc_fcntl_init(&mutex->fcntl_mutex, pathname);
    266295    }
    267296#endif
    268297
    269298#ifndef NDEBUG
    270     lck->locked = 0;
    271 #endif
    272 
    273     return lck;
    274 }
    275 /* }}} */
    276 void xc_lock_destroy(xc_lock_t *lck) /* {{{ */
    277 {
    278 #ifdef XC_LOCK_USE_PTHREAD
    279     pthread_mutex_destroy(&lck->pthread_mutex);
    280 #endif
    281 
    282 #ifdef XC_LOCK_USE_TSRM
    283     tsrm_mutex_free(lck->tsrm_mutex);
    284 #endif
    285 
    286 #ifdef XC_LOCK_USE_FCNTL
    287     if (XC_LOCK_INTERPROCESS) {
    288         xc_fcntl_destroy(&lck->fcntl_lock);
    289     }
    290 #endif
    291 }
    292 /* }}} */
    293 void xc_lock(xc_lock_t *lck) /* {{{ */
    294 {
    295 #ifdef XC_LOCK_USE_PTHREAD
    296     if (pthread_mutex_lock(&lck->pthread_mutex) < 0) {
    297         zend_error(E_ERROR, "xc_lock failed errno:%d", errno);
    298     }
    299 #endif
    300 
    301 #ifdef XC_LOCK_USE_TSRM
    302     if (tsrm_mutex_lock(lck->tsrm_mutex) < 0) {
    303         zend_error(E_ERROR, "xc_lock failed errno:%d", errno);
    304     }
    305 #endif
    306 
    307 #ifdef XC_LOCK_USE_FCNTL
    308     if (XC_LOCK_INTERPROCESS) {
    309         xc_fcntl_lock(&lck->fcntl_lock);
     299    mutex->locked = 0;
     300#endif
     301
     302    return mutex;
     303}
     304/* }}} */
     305void xc_mutex_destroy(xc_mutex_t *mutex) /* {{{ */
     306{
     307    assert(mutex);
     308
     309    /* intended to not destroy mutex when mutex is shared between process */
     310    if (!mutex->shared) {
     311#ifdef XC_MUTEX_USE_PTHREAD
     312        pthread_mutex_destroy(&mutex->pthread_mutex);
     313#endif
     314
     315#ifdef XC_MUTEX_USE_TSRM
     316        tsrm_mutex_free(mutex->tsrm_mutex);
     317#endif
     318    }
     319
     320#ifdef XC_MUTEX_USE_FCNTL
     321    if (xc_want_inter_process()) {
     322        xc_fcntl_destroy(&mutex->fcntl_mutex);
     323    }
     324#endif
     325
     326    if (!mutex->shared) {
     327        free(mutex);
     328    }
     329}
     330/* }}} */
     331void xc_mutex_lock(xc_mutex_t *mutex) /* {{{ */
     332{
     333#ifdef XC_MUTEX_USE_PTHREAD
     334    if (pthread_mutex_lock(&mutex->pthread_mutex) < 0) {
     335        zend_error(E_ERROR, "xc_mutex failed errno:%d", errno);
     336    }
     337#endif
     338
     339#ifdef XC_MUTEX_USE_TSRM
     340    if (tsrm_mutex_lock(mutex->tsrm_mutex) < 0) {
     341        zend_error(E_ERROR, "xc_mutex failed errno:%d", errno);
     342    }
     343#endif
     344
     345#ifdef XC_MUTEX_USE_FCNTL
     346    if (xc_want_inter_process()) {
     347        xc_fcntl_mutex(&mutex->fcntl_mutex);
    310348    }
    311349#endif
    312350
    313351#ifndef NDEBUG
    314     assert(!lck->locked);
    315     lck->locked = 1;
    316     assert(lck->locked);
    317 #endif
    318 }
    319 /* }}} */
    320 void xc_rdlock(xc_lock_t *lck) /* {{{ */
    321 {
    322 #ifdef XC_LOCK_USE_PTHREAD
    323     if (pthread_mutex_lock(&lck->pthread_mutex) < 0) {
    324         zend_error(E_ERROR, "xc_rdlock failed errno:%d", errno);
    325     }
    326 #endif
    327 
    328 #ifdef XC_LOCK_USE_TSRM
    329     if (tsrm_mutex_lock(lck->tsrm_mutex) < 0) {
    330         zend_error(E_ERROR, "xc_rdlock failed errno:%d", errno);
    331     }
    332 #endif
    333 
    334 #ifdef XC_LOCK_USE_FCNTL
    335     if (XC_LOCK_INTERPROCESS) {
    336         xc_fcntl_lock(&lck->fcntl_lock);
    337     }
    338 #endif
    339 
     352    assert(!mutex->locked);
     353    mutex->locked = 1;
     354    assert(mutex->locked);
     355#endif
     356}
     357/* }}} */
     358void xc_mutex_unlock(xc_mutex_t *mutex) /* {{{ */
     359{
    340360#ifndef NDEBUG
    341     assert(!lck->locked);
    342     lck->locked = 1;
    343     assert(lck->locked);
    344 #endif
    345 }
    346 /* }}} */
    347 void xc_unlock(xc_lock_t *lck) /* {{{ */
    348 {
    349 #ifndef NDEBUG
    350     assert(lck->locked);
    351     lck->locked = 0;
    352     assert(!lck->locked);
    353 #endif
    354 
    355 #ifdef XC_LOCK_USE_FCNTL
    356     if (XC_LOCK_INTERPROCESS) {
    357         xc_fcntl_unlock(&lck->fcntl_lock);
    358     }
    359 #endif
    360 
    361 #ifdef XC_LOCK_USE_TSRM
    362     if (tsrm_mutex_unlock(lck->tsrm_mutex) < 0) {
    363         zend_error(E_ERROR, "xc_unlock failed errno:%d", errno);
    364     }
    365 #endif
    366 
    367 #ifdef XC_LOCK_USE_PTHREAD
    368     if (pthread_mutex_unlock(&lck->pthread_mutex) < 0) {
    369         zend_error(E_ERROR, "xc_unlock failed errno:%d", errno);
    370     }
    371 #endif
    372 }
    373 /* }}} */
     361    assert(mutex->locked);
     362    mutex->locked = 0;
     363    assert(!mutex->locked);
     364#endif
     365
     366#ifdef XC_MUTEX_USE_FCNTL
     367    if (xc_want_inter_process()) {
     368        xc_fcntl_unlock(&mutex->fcntl_mutex);
     369    }
     370#endif
     371
     372#ifdef XC_MUTEX_USE_TSRM
     373    if (tsrm_mutex_unlock(mutex->tsrm_mutex) < 0) {
     374        zend_error(E_ERROR, "xc_mutex_unlock failed errno:%d", errno);
     375    }
     376#endif
     377
     378#ifdef XC_MUTEX_USE_PTHREAD
     379    if (pthread_mutex_unlock(&mutex->pthread_mutex) < 0) {
     380        zend_error(E_ERROR, "xc_mutex_unlock failed errno:%d", errno);
     381    }
     382#endif
     383}
     384/* }}} */
Note: See TracChangeset for help on using the changeset viewer.