LCOV - code coverage report
Current view: top level - utils - partiallock.cc (source / functions) Hit Total Coverage
Test: coverage.info.cleaned Lines: 69 97 71.1 %
Date: 2015-01-12 15:17:13 Functions: 4 4 100.0 %
Branches: 24 40 60.0 %

           Branch data     Line data    Source code
       1                 :            : /* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
       2                 :            : /*
       3                 :            :  * Generic Partial Lock
       4                 :            :  * see https://github.com/greensky00/partiallock
       5                 :            :  */
       6                 :            : 
       7                 :            : #include <stdio.h>
       8                 :            : #include <stdlib.h>
       9                 :            : #include <string.h>
      10                 :            : 
      11                 :            : #include "partiallock.h"
      12                 :            : 
      13                 :            : struct plock_node {
      14                 :            :     void *lock;
      15                 :            :     void *start;
      16                 :            :     void *len;
      17                 :            :     volatile uint32_t wcount; // waiting count
      18                 :            :     struct list_elem le;
      19                 :            : };
      20                 :            : 
      21                 :        248 : int plock_init(struct plock *plock, struct plock_config *config)
      22                 :            : {
      23 [ +  - ][ -  + ]:        248 :     if (!plock || !config) {
      24                 :          0 :         return PLOCK_RESULT_INVALID_ARGS;
      25                 :            :     }
      26                 :            : 
      27                 :        248 :     plock->ops = (struct plock_ops *)malloc(sizeof(struct plock_ops));
      28         [ -  + ]:        248 :     if (!plock->ops) {
      29                 :          0 :         return PLOCK_RESULT_ALLOC_FAIL;
      30                 :            :     }
      31                 :        248 :     *plock->ops = *(config->ops);
      32                 :            : 
      33                 :            :     // allocate and init lock
      34                 :        248 :     plock->sizeof_lock_user = config->sizeof_lock_user;
      35                 :        248 :     plock->sizeof_lock_internal = config->sizeof_lock_internal;
      36                 :        248 :     plock->sizeof_range = config->sizeof_range;
      37                 :        248 :     plock->aux = config->aux;
      38                 :        248 :     plock->lock = (void *)malloc(plock->sizeof_lock_internal);
      39                 :        248 :     plock->ops->init_internal(plock->lock);
      40                 :            : 
      41                 :            :     // init list and tree
      42                 :        248 :     list_init(&plock->active);
      43                 :        248 :     list_init(&plock->inactive);
      44                 :            : 
      45                 :        248 :     return PLOCK_RESULT_SUCCESS;
      46                 :            : }
      47                 :            : 
      48                 :    7685349 : plock_entry_t *plock_lock(struct plock *plock, void *start, void *len)
      49                 :            : {
      50                 :    7685349 :     struct list_elem *le = NULL;
      51                 :    7685349 :     struct plock_node *node = NULL;
      52                 :            : 
      53 [ +  + ][ +  - ]:    7685349 :     if (!plock || !start || !len) {
                 [ -  + ]
      54                 :          0 :         return NULL;
      55                 :            :     }
      56                 :            : 
      57                 :            :     // grab plock's lock
      58                 :    7685349 :     plock->ops->lock_internal(plock->lock);
      59                 :            : 
      60                 :            :     // find existing overlapped lock
      61                 :    7685490 :     le = list_begin(&plock->active);
      62         [ +  + ]:   11949413 :     while (le) {
      63                 :    4263923 :         node = _get_entry(le, struct plock_node, le);
      64         [ -  + ]:    4263923 :         if (plock->ops->is_overlapped(node->start, node->len,
      65                 :    4263923 :                                       start, len, plock->aux)) {
      66                 :            :             // overlapped
      67                 :            :             // increase waiting count
      68                 :          0 :             node->wcount++;
      69                 :            :             // release plock's lock
      70                 :          0 :             plock->ops->unlock_internal(plock->lock);
      71                 :            : 
      72                 :            :             // grab node's lock
      73                 :          0 :             plock->ops->lock_user(node->lock);
      74                 :            :             // got control .. that means the owner released the lock
      75                 :            :             // grab plock's lock
      76                 :          0 :             plock->ops->lock_internal(plock->lock);
      77                 :            :             // decrease waiting count
      78                 :          0 :             le = list_next(&node->le);
      79                 :          0 :             node->wcount--;
      80         [ #  # ]:          0 :             if (node->wcount == 0) {
      81                 :            :                 // no other thread refers this node
      82                 :            :                 // move from active to inactive
      83                 :          0 :                 list_remove(&plock->active, &node->le);
      84                 :          0 :                 list_push_front(&plock->inactive, &node->le);
      85                 :            :             }
      86                 :            :             // release node's lock
      87                 :          0 :             plock->ops->unlock_user(node->lock);
      88                 :            :         } else {
      89                 :    4263923 :             le = list_next(le);
      90                 :            :         }
      91                 :            :     }
      92                 :            : 
      93                 :            :     // get a free lock
      94                 :    7685490 :     le = list_pop_front(&plock->inactive);
      95         [ +  + ]:    7685490 :     if (le == NULL) {
      96                 :            :         // no free lock .. create one
      97                 :        103 :         node = (struct plock_node *)malloc(sizeof(struct plock_node));
      98         [ -  + ]:        103 :         if (!node) {
      99                 :          0 :             plock->ops->unlock_internal(plock->lock);
     100                 :          0 :             return NULL;
     101                 :            :         }
     102                 :        103 :         node->lock = (void *)malloc(plock->sizeof_lock_user);
     103                 :        103 :         plock->ops->init_user(node->lock);
     104                 :        103 :         node->start = (void *)malloc(plock->sizeof_range);
     105                 :        103 :         node->len = (void *)malloc(plock->sizeof_range);
     106 [ +  - ][ +  - ]:        103 :         if (!node->lock || !node->start || !node->len) {
                 [ -  + ]
     107                 :          0 :             free(node);
     108                 :          0 :             plock->ops->unlock_internal(plock->lock);
     109                 :          0 :             return NULL;
     110                 :            :         }
     111                 :            :     } else {
     112                 :    7685387 :         node = _get_entry(le, struct plock_node ,le);
     113                 :            :     }
     114                 :    7685490 :     node->wcount = 0;
     115                 :            : 
     116                 :            :     // copy start & len value
     117                 :    7685490 :     memcpy(node->start, start, plock->sizeof_range);
     118                 :    7685490 :     memcpy(node->len, len, plock->sizeof_range);
     119                 :            :     // insert into active list
     120                 :    7685490 :     list_push_back(&plock->active, &node->le);
     121                 :            : 
     122                 :            :     // grab node's lock & release plock's lock
     123                 :    7685490 :     plock->ops->lock_user(node->lock);
     124                 :    7685490 :     plock->ops->unlock_internal(plock->lock);
     125                 :            : 
     126                 :    7685490 :     return node;
     127                 :            : }
     128                 :            : 
     129                 :    7680051 : int plock_unlock(struct plock *plock, plock_entry_t *plock_entry)
     130                 :            : {
     131                 :    7680051 :     struct plock_node *node = plock_entry;
     132                 :            : 
     133 [ +  + ][ -  + ]:    7680051 :     if (!plock || !plock_entry) {
     134                 :          0 :         return PLOCK_RESULT_INVALID_ARGS;
     135                 :            :     }
     136                 :            : 
     137                 :            :     // grab plock's lock
     138                 :    7680051 :     plock->ops->lock_internal(plock->lock);
     139                 :            : 
     140         [ +  - ]:    7685490 :     if (node->wcount == 0) {
     141                 :            :         // no other thread refers this node
     142                 :            :         // move from active to inactive
     143                 :    7685490 :         list_remove(&plock->active, &node->le);
     144                 :    7685490 :         list_push_front(&plock->inactive, &node->le);
     145                 :            :     }
     146                 :    7685490 :     plock->ops->unlock_user(node->lock);
     147                 :            : 
     148                 :            :     // release plock's lock
     149                 :    7685490 :     plock->ops->unlock_internal(plock->lock);
     150                 :            : 
     151                 :    7684224 :     return PLOCK_RESULT_SUCCESS;
     152                 :            : }
     153                 :            : 
     154                 :        247 : int plock_destroy(struct plock *plock)
     155                 :            : {
     156                 :            :     struct list_elem *le;
     157                 :            :     struct plock_node *node;
     158                 :            : 
     159         [ -  + ]:        247 :     if (!plock) {
     160                 :          0 :         return PLOCK_RESULT_INVALID_ARGS;
     161                 :            :     }
     162                 :            : 
     163                 :        247 :     plock->ops->destroy_internal(plock->lock);
     164                 :            : 
     165                 :            :     // free all active locks
     166                 :        247 :     le = list_begin(&plock->active);
     167         [ -  + ]:        247 :     while(le) {
     168                 :          0 :         node = _get_entry(le, struct plock_node, le);
     169                 :          0 :         le = list_next(le);
     170                 :            : 
     171                 :            :         // unlock and destroy
     172                 :          0 :         plock->ops->unlock_user(node->lock);
     173                 :          0 :         plock->ops->destroy_user(node->lock);
     174                 :          0 :         free(node->start);
     175                 :          0 :         free(node->len);
     176                 :          0 :         free(node->lock);
     177                 :          0 :         free(node);
     178                 :            :     }
     179                 :            : 
     180                 :            :     // free all inactive locks
     181                 :        247 :     le = list_begin(&plock->inactive);
     182         [ +  + ]:        350 :     while(le) {
     183                 :        103 :         node = _get_entry(le, struct plock_node, le);
     184                 :        103 :         le = list_next(le);
     185                 :            : 
     186                 :            :         // destroy
     187                 :        103 :         plock->ops->destroy_user(node->lock);
     188                 :        103 :         free(node->start);
     189                 :        103 :         free(node->len);
     190                 :        103 :         free(node->lock);
     191                 :        103 :         free(node);
     192                 :            :     }
     193                 :            : 
     194                 :            :     // free plock
     195                 :        247 :     free(plock->lock);
     196                 :        247 :     free(plock->ops);
     197                 :            : 
     198                 :        247 :     return PLOCK_RESULT_SUCCESS;
     199                 :            : }
     200                 :            : 

Generated by: LCOV version 1.11