LCOV - code coverage report
Current view: top level - pulsecore - flist.c (source / functions) Hit Total Coverage
Test: lcov.out Lines: 56 60 93.3 %
Date: 2012-07-17 Functions: 7 7 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 24 41 58.5 %

           Branch data     Line data    Source code
       1                 :            : /***
       2                 :            :   This file is part of PulseAudio.
       3                 :            : 
       4                 :            :   Copyright 2006-2008 Lennart Poettering
       5                 :            :   Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies).
       6                 :            :   Copyright (C) 2012 Canonical Ltd.
       7                 :            : 
       8                 :            :   Contact: Jyri Sarha <Jyri.Sarha@nokia.com>
       9                 :            : 
      10                 :            :   PulseAudio is free software; you can redistribute it and/or modify
      11                 :            :   it under the terms of the GNU Lesser General Public License as
      12                 :            :   published by the Free Software Foundation; either version 2.1 of the
      13                 :            :   License, or (at your option) any later version.
      14                 :            : 
      15                 :            :   PulseAudio is distributed in the hope that it will be useful, but
      16                 :            :   WITHOUT ANY WARRANTY; without even the implied warranty of
      17                 :            :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      18                 :            :   Lesser General Public License for more details.
      19                 :            : 
      20                 :            :   You should have received a copy of the GNU Lesser General Public
      21                 :            :   License along with PulseAudio; if not, write to the Free Software
      22                 :            :   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
      23                 :            :   USA.
      24                 :            : ***/
      25                 :            : 
      26                 :            : #ifdef HAVE_CONFIG_H
      27                 :            : #include <config.h>
      28                 :            : #endif
      29                 :            : 
      30                 :            : #include <pulse/xmalloc.h>
      31                 :            : 
      32                 :            : #include <pulsecore/atomic.h>
      33                 :            : #include <pulsecore/log.h>
      34                 :            : #include <pulsecore/macro.h>
      35                 :            : #include <pulsecore/core-util.h>
      36                 :            : #include <pulsecore/macro.h>
      37                 :            : 
      38                 :            : #include "flist.h"
      39                 :            : 
      40                 :            : #define FLIST_SIZE 128
      41                 :            : 
      42                 :            : /* Atomic table indices contain
      43                 :            :    sign bit = if set, indicates empty/NULL value
      44                 :            :    tag bits (to avoid the ABA problem)
      45                 :            :    actual index bits
      46                 :            : */
      47                 :            : 
      48                 :            : /* Lock free single linked list element. */
      49                 :            : struct pa_flist_elem {
      50                 :            :     pa_atomic_t next;
      51                 :            :     pa_atomic_ptr_t ptr;
      52                 :            : };
      53                 :            : 
      54                 :            : typedef struct pa_flist_elem pa_flist_elem;
      55                 :            : 
      56                 :            : struct pa_flist {
      57                 :            :     char *name;
      58                 :            :     unsigned size;
      59                 :            : 
      60                 :            :     pa_atomic_t current_tag;
      61                 :            :     int index_mask;
      62                 :            :     int tag_shift;
      63                 :            :     int tag_mask;
      64                 :            : 
      65                 :            :     /* Stack that contains pointers stored into free list */
      66                 :            :     pa_atomic_t stored;
      67                 :            :     /* Stack that contains empty list elements */
      68                 :            :     pa_atomic_t empty;
      69                 :            :     pa_flist_elem table[];
      70                 :            : };
      71                 :            : 
      72                 :            : /* Lock free pop from linked list stack */
      73                 :       1770 : static pa_flist_elem *stack_pop(pa_flist *flist, pa_atomic_t *list) {
      74                 :            :     pa_flist_elem *popped;
      75                 :            :     int idx;
      76         [ -  + ]:       1770 :     pa_assert(list);
      77                 :            : 
      78                 :            :     do {
      79                 :       1770 :         idx = pa_atomic_load(list);
      80         [ +  + ]:       1770 :         if (idx < 0)
      81                 :            :             return NULL;
      82                 :       1711 :         popped = &flist->table[idx & flist->index_mask];
      83         [ -  + ]:       1770 :     } while (!pa_atomic_cmpxchg(list, idx, pa_atomic_load(&popped->next)));
      84                 :            : 
      85                 :            :     return popped;
      86                 :            : }
      87                 :            : 
      88                 :            : /* Lock free push to linked list stack */
      89                 :      13230 : static void stack_push(pa_flist *flist, pa_atomic_t *list, pa_flist_elem *new_elem) {
      90                 :            :     int tag, newindex, next;
      91         [ -  + ]:      13230 :     pa_assert(list);
      92                 :            : 
      93                 :      26460 :     tag = pa_atomic_inc(&flist->current_tag);
      94                 :      13230 :     newindex = new_elem - flist->table;
      95    [ +  - ][ + ]:      13230 :     pa_assert(newindex >= 0 && newindex < (int) flist->size);
      96                 :      13231 :     newindex |= (tag << flist->tag_shift) & flist->tag_mask;
      97                 :            : 
      98                 :            :     do {
      99                 :      13231 :         next = pa_atomic_load(list);
     100                 :      13231 :         pa_atomic_store(&new_elem->next, next);
     101         [ -  + ]:      13231 :     } while (!pa_atomic_cmpxchg(list, next, newindex));
     102                 :      13231 : }
     103                 :            : 
     104                 :         20 : pa_flist *pa_flist_new_with_name(unsigned size, const char *name) {
     105                 :            :     pa_flist *l;
     106                 :            :     unsigned i;
     107         [ -  + ]:         20 :     pa_assert(name);
     108                 :            : 
     109         [ +  + ]:         20 :     if (!size)
     110                 :         10 :         size = FLIST_SIZE;
     111                 :            : 
     112                 :         20 :     l = pa_xmalloc0(sizeof(pa_flist) + sizeof(pa_flist_elem) * size);
     113                 :            : 
     114                 :         20 :     l->name = pa_xstrdup(name);
     115                 :         20 :     l->size = size;
     116                 :            : 
     117         [ +  + ]:        190 :     while (1 << l->tag_shift < (int) size)
     118                 :        170 :         l->tag_shift++;
     119                 :         20 :     l->index_mask = (1 << l->tag_shift) - 1;
     120                 :         20 :     l->tag_mask = INT_MAX - l->index_mask;
     121                 :            : 
     122                 :         20 :     pa_atomic_store(&l->stored, -1);
     123                 :         20 :     pa_atomic_store(&l->empty, -1);
     124         [ +  + ]:      11540 :     for (i=0; i < size; i++) {
     125                 :      11520 :         stack_push(l, &l->empty, &l->table[i]);
     126                 :            :     }
     127                 :         20 :     return l;
     128                 :            : }
     129                 :            : 
     130                 :         10 : pa_flist *pa_flist_new(unsigned size) {
     131                 :         10 :     return pa_flist_new_with_name(size, "unknown");
     132                 :            : }
     133                 :            : 
     134                 :          9 : void pa_flist_free(pa_flist *l, pa_free_cb_t free_cb) {
     135         [ -  + ]:          9 :     pa_assert(l);
     136         [ -  + ]:          9 :     pa_assert(l->name);
     137                 :            : 
     138         [ -  + ]:          9 :     if (free_cb) {
     139                 :            :         pa_flist_elem *elem;
     140         [ #  # ]:          0 :         while((elem = stack_pop(l, &l->stored)))
     141                 :          0 :             free_cb(pa_atomic_ptr_load(&elem->ptr));
     142                 :            :     }
     143                 :            : 
     144                 :          9 :     pa_xfree(l->name);
     145                 :          9 :     pa_xfree(l);
     146                 :          9 : }
     147                 :            : 
     148                 :        882 : int pa_flist_push(pa_flist *l, void *p) {
     149                 :            :     pa_flist_elem *elem;
     150         [ -  + ]:        882 :     pa_assert(l);
     151         [ -  + ]:        882 :     pa_assert(p);
     152                 :            : 
     153                 :        882 :     elem = stack_pop(l, &l->empty);
     154         [ -  + ]:        882 :     if (elem == NULL) {
     155         [ #  # ]:          0 :         if (pa_log_ratelimit(PA_LOG_DEBUG))
     156                 :          0 :             pa_log_debug("%s flist is full (don't worry)", l->name);
     157                 :            :         return -1;
     158                 :            :     }
     159                 :        882 :     pa_atomic_ptr_store(&elem->ptr, p);
     160                 :        882 :     stack_push(l, &l->stored, elem);
     161                 :            : 
     162                 :        882 :     return 0;
     163                 :            : }
     164                 :            : 
     165                 :        888 : void* pa_flist_pop(pa_flist *l) {
     166                 :            :     pa_flist_elem *elem;
     167                 :            :     void *ptr;
     168         [ -  + ]:        888 :     pa_assert(l);
     169                 :            : 
     170                 :        888 :     elem = stack_pop(l, &l->stored);
     171         [ +  + ]:        888 :     if (elem == NULL)
     172                 :            :         return NULL;
     173                 :            : 
     174                 :       1658 :     ptr = pa_atomic_ptr_load(&elem->ptr);
     175                 :            : 
     176                 :        829 :     stack_push(l, &l->empty, elem);
     177                 :            : 
     178                 :        888 :     return ptr;
     179                 :            : }

Generated by: LCOV version 1.9