LCOV - code coverage report
Current view: top level - Core - OOAsyncQueue.m (source / functions) Hit Total Coverage
Test: coverxygen.info Lines: 0 16 0.0 %
Date: 2025-05-28 07:50:54 Functions: 0 0 -

          Line data    Source code
       1           0 : /*
       2             : 
       3             : OOAsyncQueue.m
       4             : By Jens Ayton
       5             : 
       6             : 
       7             : Copyright (C) 2007-2013 Jens Ayton
       8             : 
       9             : Permission is hereby granted, free of charge, to any person obtaining a copy
      10             : of this software and associated documentation files (the "Software"), to deal
      11             : in the Software without restriction, including without limitation the rights
      12             : to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
      13             : copies of the Software, and to permit persons to whom the Software is
      14             : furnished to do so, subject to the following conditions:
      15             : 
      16             : The above copyright notice and this permission notice shall be included in all
      17             : copies or substantial portions of the Software.
      18             : 
      19             : THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
      20             : IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
      21             : FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
      22             : AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
      23             : LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
      24             : OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
      25             : SOFTWARE.
      26             : 
      27             : */
      28             : 
      29             : #include <assert.h>
      30             : 
      31             : #import "OOAsyncQueue.h"
      32             : #import "OOFunctionAttributes.h"
      33             : #import "OOLogging.h"
      34             : #import "NSThreadOOExtensions.h"
      35             : #include <stdlib.h>
      36             : 
      37             : #ifndef OO_BUGGY_PTHREADS
      38             : #if OOLITE_WINDOWS
      39             : // Maybe add #if OOLITE_64_BIT too?
      40             : #define OO_BUGGY_PTHREADS 1
      41             : #else
      42           0 : #define OO_BUGGY_PTHREADS 0
      43             : #endif
      44             : #endif
      45             : 
      46           0 : enum
      47             : {
      48             :         kConditionNoData                = 1,
      49             :         kConditionQueuedData,
      50             :         kConditionDead
      51             : };
      52             : 
      53             : 
      54           0 : enum
      55             : {
      56             :         kMaxPoolElements                = 5
      57             : };
      58             : 
      59             : 
      60           0 : typedef struct OOAsyncQueueElement OOAsyncQueueElement;
      61           0 : struct OOAsyncQueueElement
      62             : {
      63           0 :         OOAsyncQueueElement     *next;
      64           0 :         id                                      object;
      65             : };
      66             : 
      67             : 
      68           0 : OOINLINE OOAsyncQueueElement *AllocElement(void)
      69             : {
      70             :         return malloc(sizeof (OOAsyncQueueElement));
      71             : }
      72             : 
      73             : 
      74           0 : OOINLINE void FreeElement(OOAsyncQueueElement *element)
      75             : {
      76             :         free(element);
      77             : }
      78             : 
      79             : 
      80             : @interface OOAsyncQueue (OOPrivate)
      81             : 
      82           0 : - (void)doEmptyQueueWithAcquiredLock;
      83           0 : - (id)doDequeAndUnlockWithAcquiredLock;
      84           0 : - (void)recycleElementWithAcquiredLock:(OOAsyncQueueElement *)element;
      85             : 
      86             : @end
      87             : 
      88             : 
      89             : @implementation OOAsyncQueue
      90             : 
      91           0 : - (id)init
      92             : {
      93             :         self = [super init];
      94             :         if (self != nil)
      95             :         {
      96             :                 _lock = [[NSConditionLock alloc] initWithCondition:kConditionNoData];
      97             :                 [_lock setName:@"OOAsyncQueue lock"];
      98             :                 if (_lock == nil)
      99             :                 {
     100             :                         [self release];
     101             :                         self = nil;
     102             :                 }
     103             :         }
     104             :         
     105             :         return self;
     106             : }
     107             : 
     108             : 
     109           0 : - (void)dealloc
     110             : {
     111             :         OOAsyncQueueElement             *element = NULL;
     112             :         
     113             :         [_lock lock];
     114             :         
     115             :         if (_elemCount != 0)
     116             :         {
     117             :                 OOLogWARN(@"asyncQueue.nonEmpty", @"%@ deallocated while non-empty, flushing.", self);
     118             :                 [self doEmptyQueueWithAcquiredLock];
     119             :         }
     120             :         
     121             :         // Free element pool.
     122             :         while (_pool != NULL)
     123             :         {
     124             :                 element = _pool;
     125             :                 _pool = element->next;
     126             :                 free(element);
     127             :         }
     128             :         
     129             :         [_lock unlockWithCondition:kConditionDead];
     130             :         [_lock release];
     131             :         
     132             :         [super dealloc];
     133             : }
     134             : 
     135             : 
     136           0 : - (NSString *)description
     137             : {
     138             :         // Don't bother locking, the value would be out of date immediately anyway.
     139             :         return [NSString stringWithFormat:@"<%@ %p>{%u elements}", [self class], self, _elemCount];
     140             : }
     141             : 
     142             : 
     143             : - (BOOL)enqueue:(id)object
     144             : {
     145             :         OOAsyncQueueElement             *element = NULL;
     146             :         BOOL                                    success = NO;
     147             :         
     148             :         if (EXPECT_NOT(object == nil))  return NO;
     149             :         
     150             :         [_lock lock];
     151             :         
     152             :         // Get an element.
     153             :         if (_pool != NULL)
     154             :         {
     155             :                 element = _pool;
     156             :                 _pool = element->next;
     157             :                 --_poolCount;
     158             :         }
     159             :         else
     160             :         {
     161             :                 element = AllocElement();
     162             :                 if (element == NULL)  goto FAIL;
     163             :         }
     164             :         
     165             :         // Set element fields.
     166             :         element->object = [object retain];
     167             :         element->next = NULL;
     168             :         
     169             :         // Insert in queue.
     170             :         if (_head == NULL)
     171             :         {
     172             :                 // Queue was empty, element is entire queue.
     173             :                 _head = _tail = element;
     174             :                 element->next = NULL;
     175             :                 assert(_elemCount == 0);
     176             :                 _elemCount = 1;
     177             :         }
     178             :         else
     179             :         {
     180             :                 assert(_tail != NULL);
     181             :                 assert(_tail->next == NULL);
     182             :                 assert(_elemCount != 0);
     183             :                 
     184             :                 _tail->next = element;
     185             :                 _tail = element;
     186             :                 ++_elemCount;
     187             :         }
     188             :         success = YES;
     189             :         
     190             : FAIL:
     191             :         [_lock unlockWithCondition:kConditionQueuedData];
     192             :         return success;
     193             : }
     194             : 
     195             : 
     196             : - (id)dequeue
     197             : {
     198             :         [_lock lockWhenCondition:kConditionQueuedData];
     199             :         return [self doDequeAndUnlockWithAcquiredLock];
     200             : }
     201             : 
     202             : 
     203             : - (id)tryDequeue
     204             : {
     205             : #if OO_BUGGY_PTHREADS
     206             : /* pthread_mutex_trylock is buggy on 64-bit windows with the pthread
     207             :  * library in use, so avoid doing things which use it This is a little
     208             :  * more blocking, but no thread should be hanging on to _lock for very
     209             :  * long, so hopefully it won't be noticeable.
     210             :  */
     211             :         [_lock lock];
     212             :         if ([_lock condition] != kConditionQueuedData)
     213             :         {
     214             :                 [_lock unlock];
     215             :                 return NO;
     216             :         }
     217             : #else
     218             :         // Mac and Linux can do it properly
     219             :         if (![_lock tryLockWhenCondition:kConditionQueuedData])  return nil;
     220             : #endif
     221             :         return [self doDequeAndUnlockWithAcquiredLock];
     222             : }
     223             : 
     224             : 
     225             : - (BOOL)empty
     226             : {
     227             :         return _head != NULL;
     228             : }
     229             : 
     230             : 
     231             : - (unsigned)count
     232             : {
     233             :         return _elemCount;
     234             : }
     235             : 
     236             : 
     237             : - (void)emptyQueue
     238             : {
     239             :         [_lock lock];
     240             :         [self doEmptyQueueWithAcquiredLock];
     241             :         
     242             :         assert(_head == NULL && _tail == NULL && _elemCount == 0);
     243             :         [_lock unlockWithCondition:kConditionNoData];
     244             : }
     245             : 
     246             : @end
     247             : 
     248             : 
     249             : @implementation OOAsyncQueue (OOPrivate)
     250             : 
     251             : - (void)doEmptyQueueWithAcquiredLock
     252             : {
     253             :         OOAsyncQueueElement             *element = NULL;
     254             :         
     255             :         // Loop over queue.
     256             :         while (_head != NULL)
     257             :         {
     258             :                 // Dequeue element.
     259             :                 element = _head;
     260             :                 _head = _head->next;
     261             :                 --_elemCount;
     262             :                 
     263             :                 // We don't need the payload any longer.
     264             :                 [element->object release];
     265             :                 
     266             :                 // Or the element.
     267             :                 [self recycleElementWithAcquiredLock:element];
     268             :         }
     269             :         
     270             :         _tail = NULL;
     271             : }
     272             : 
     273             : 
     274             : - (id)doDequeAndUnlockWithAcquiredLock
     275             : {
     276             :         OOAsyncQueueElement             *element = NULL;
     277             :         id                                              result;
     278             :         
     279             :         if (_head == NULL)
     280             :         {
     281             :                 // Can happen if you enter debugger.
     282             :                 return nil;
     283             :         }
     284             :         
     285             : //      assert(_head != NULL);
     286             :         
     287             :         // Dequeue element.
     288             :         element = _head;
     289             :         _head = _head->next;
     290             :         if (_head == NULL)  _tail = NULL;
     291             :         --_elemCount;
     292             :         
     293             :         // Unpack payload.
     294             :         result = [element->object autorelease];
     295             :         
     296             :         // Recycle element.
     297             :         [self recycleElementWithAcquiredLock:element];
     298             :         
     299             :         // Ensure sane status.
     300             :         assert((_head == NULL && _tail == NULL && _elemCount == 0) || (_head != NULL && _tail != NULL && _elemCount != 0));
     301             :         
     302             :         // Unlock with appropriate state.
     303             :         [_lock unlockWithCondition:(_head == NULL) ? kConditionNoData : kConditionQueuedData];
     304             :         
     305             :         return result;
     306             : }
     307             : 
     308             : 
     309             : - (void)recycleElementWithAcquiredLock:(OOAsyncQueueElement *)element
     310             : {
     311             :         if (_poolCount < kMaxPoolElements)
     312             :         {
     313             :                 // Add to pool for reuse.
     314             :                 element->next = _pool;
     315             :                 _pool = element;
     316             :                 ++_poolCount;
     317             :         }
     318             :         else
     319             :         {
     320             :                 // Delete.
     321             :                 FreeElement(element);
     322             :         }
     323             : }
     324             : 
     325             : @end

Generated by: LCOV version 1.14