Ignore:
Timestamp:
2013-09-09T18:16:05+02:00 (16 months ago)
Author:
moo
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.