Esempio n. 1
0
/**
 * This callback is called whenver an FSEvents watch is triggered
 */
static void watch_callback(
    ConstFSEventStreamRef streamRef,
    void *info,
    size_t numEvents,
    void *eventPaths,
    const FSEventStreamEventFlags eventFlags[],
    const FSEventStreamEventId eventIds[]) {
  struct thread_env *thread_env = (struct thread_env *)info;
  int i;
  char **paths = eventPaths;
  CFStringRef cf_wpath;
  CFArrayRef paths_watched;
  CFIndex wpath_len;
  int path_len;
  struct event *ev;

  for (i = 0; i < numEvents; i++) {
    paths_watched = FSEventStreamCopyPathsBeingWatched(streamRef);
    if (CFArrayGetCount(paths_watched) < 1) {
      continue;
    }
    // Create an event with the info from FSEvents
    ev = malloc(sizeof(struct event));
    cf_wpath = CFArrayGetValueAtIndex(paths_watched, 0);
    wpath_len = CFStringGetLength(cf_wpath);
    ev->wpath = malloc(wpath_len + 1);
    CFStringGetCString(
        cf_wpath,
        ev->wpath,
        wpath_len + 1,
        kCFStringEncodingMacRoman
    );
    path_len = strlen(paths[i]);
    ev->path = malloc(path_len + 1);
    strcpy(ev->path, paths[i]);

    // Update the lockless linked list of events
    ev->next = *(thread_env->events);
    if (OSAtomicCompareAndSwapPtr(ev->next, ev, (void *)(thread_env->events)) == false) {
      // The only thing the main thread can write to events is NULL, so we can just
      // try one more time
      ev->next = NULL;
      if (OSAtomicCompareAndSwapPtr(ev->next, ev, (void *)(thread_env->events)) == false) {
        // This should never happen
        fprintf(stderr, "Unexpected error with fsevents lockless events list\n");
      }
    }
    signal_on_pipe(thread_env->write_event_fd);
  }
}
Esempio n. 2
0
/**
 * The callback for when the main thread has issued a command to the run loop
 * thread. Reads all the pending commands and executes them
 */
static void command_callback(
    CFFileDescriptorRef fdref,
    CFOptionFlags callBackTypes,
    void *context) {
  int fd = CFFileDescriptorGetNativeDescriptor(fdref);
  struct thread_env *thread_env = (struct thread_env *)context;
  struct command *to_do = NULL;
  struct command *to_free = NULL;
  clear_pipe(fd);
  do {
    to_do = *(thread_env->commands);
  } while (OSAtomicCompareAndSwapPtr(to_do, NULL, (void *)(thread_env->commands)) == false);
  while (to_do != NULL) {
    switch (to_do->type) {
      case ADD_WATCH:
        add_watch(to_do->arg, thread_env);
        break;
      case RM_WATCH:
        // hh_server doesn't need this at the moment. Shouldn't be too hard to
        // do...just need to map of paths to FSEvent streams.
        fprintf(stderr, "fsevents impl doesn't support removing watches yet\n");
        break;
    }
    to_free = to_do;
    to_do = to_do->next;
    free(to_free->arg);
    free(to_free);
  }
  // For some reason you have to re-enable this callback every bloody time
  CFFileDescriptorEnableCallBacks(fdref, kCFFileDescriptorReadCallBack);
}
Esempio n. 3
0
/**
 \brief use this method to reserve a blob of data to fill.
 \param inCount count of bytes you need to reserve
 \param inOutRangeList RangeList to hold new state
 
 This method should only be called from the storing thread
 */
LockFreeQueueReturnCode    LockFreeQueue::ReserveRange(unsigned long inCount, RangeList* inOutRangeList)
{
    OSMemoryBarrier();

    RangeList *oldRangeList = (RangeList*)mRangeList;
    
    if (oldRangeList == inOutRangeList)
    {
        printf("reserve: RangeList in use!\n");
        return LockFreeQueue_rangeListInUse;
    }
    
    if (oldRangeList)
    {
        if (oldRangeList->mHasReserved)
        {
            // someone has already reserved space, try again later!
            return LockFreeQueue_alreadyReserved;
        }
        
        if (FreeBytesWithList(oldRangeList) < inCount)
        {
            // not enough space!
            return LockFreeQueue_notEnoughSpaceLeft;
        }
        
        memcpy(inOutRangeList, oldRangeList, sizeof(RangeList));
    }
    else
    {
        memset(inOutRangeList, 0, sizeof(RangeList));
    }

    unsigned long firstReserved = FirstEmptyByteIndexWithList(inOutRangeList);
    inOutRangeList->mReservedRange.mPosition = firstReserved;
    inOutRangeList->mReservedRange.mLength = inCount;
    inOutRangeList->mHasReserved = true;
    
    bool result = OSAtomicCompareAndSwapPtr(oldRangeList, inOutRangeList, (void* volatile*)&mRangeList);
    
    if (result && true)
    {
        Range firstByteRange;
        Range secondByteRange;
        
        RangePartsOfByteRange(&firstByteRange, &secondByteRange, &inOutRangeList->mReservedRange);
        
        if (secondByteRange.mLength == 0)
        {
            memset(&(mDataRing[firstByteRange.mPosition]), 'r', inCount);
        }
        else
        {
            memset(&(mDataRing[firstByteRange.mPosition]), 'r', firstByteRange.mLength);
            memset(&(mDataRing[secondByteRange.mPosition]), 'r', inCount-firstByteRange.mLength);
        }        
    }
    
    return result ? LockFreeQueue_OK : LockFreeQueue_casUnsuccessful;
}
Esempio n. 4
0
/**
 \brief Fetch a blob of data
 \param inOutBuffer buffer to hold the fetched data
 \param inBufferLength length of supplied buffer in inOutBuffer
 \param inOutRangeList RangeList to hold new state
 \param outReturnedBytesCount count of bytes which are returned
 
 This method should only be called from the fetching thread
 */
LockFreeQueueReturnCode LockFreeQueue::Fetch(char *inOutBuffer, unsigned long inBufferLength, RangeList* inOutRangeList, unsigned long * outReturnedBytesCount)
{
    OSMemoryBarrier();
    RangeList *oldRangeList = (RangeList*)mRangeList;
    
    if (oldRangeList == inOutRangeList)
    {
        printf("fetch: RangeList in use!\n");
        *outReturnedBytesCount = 0;
        return LockFreeQueue_rangeListInUse;
    }
    
    if (oldRangeList->mFullRangeCount == 0)
    {
        // nothing to fetch!
        *outReturnedBytesCount = 0;
        return LockFreeQueue_empty;
    }

    if (oldRangeList->mFullRanges[0].mLength > inBufferLength)
    {
        printf("inBuffer not large enough!\n");
        *outReturnedBytesCount = 0;
        return LockFreeQueue_bufferToSmall;
    }

    Range firstRange;
    Range secondRange;
    
    RangePartsOfByteRange(&firstRange, &secondRange, &oldRangeList->mFullRanges[0]);
    
    const bool doClearBuffer = true;
    
    memcpy(inOutBuffer, &mDataRing[firstRange.mPosition], firstRange.mLength);
    
    if (secondRange.mLength)
    {
        memcpy(&inOutBuffer[firstRange.mLength], &mDataRing[secondRange.mPosition], secondRange.mLength);
    }

    inOutRangeList->mHasReserved = oldRangeList->mHasReserved;
    inOutRangeList->mReservedRange = oldRangeList->mReservedRange;
    for (unsigned long i=0; i+1<oldRangeList->mFullRangeCount ; i++)
    {
        inOutRangeList->mFullRanges[i] = oldRangeList->mFullRanges[i+1];
    }
    inOutRangeList->mFullRangeCount = oldRangeList->mFullRangeCount-1;
    
    bool result = OSAtomicCompareAndSwapPtr(oldRangeList, inOutRangeList, (void* volatile*)&mRangeList);
    
    if (result && doClearBuffer)
    {
        memset(&mDataRing[firstRange.mPosition], '-', firstRange.mLength);
        if (secondRange.mLength) memset(&mDataRing[secondRange.mPosition], '-', secondRange.mLength);
    }
    
    *outReturnedBytesCount = result ? oldRangeList->mFullRanges[0].mLength : 0;
    return result ? LockFreeQueue_OK : LockFreeQueue_casUnsuccessful;
}
Esempio n. 5
0
/**
 * Grabs the events that are ready to be processed from the linked list and
 * clears the list
 */
static struct event *read_events(struct env *env) {
  struct event *to_do = NULL;
  clear_pipe(env->read_event_fd);
  do {
    to_do = *(env->events);
  } while (OSAtomicCompareAndSwapPtr(to_do, NULL, (void *)(env->events)) == false);
  return to_do;
}
Esempio n. 6
0
/**
 * Sends a command to the run loop thread by adding the command to the linked
 * list of commands and then signaling the run loop thread through a pipe
 */
static void send_command(struct env *env, command_type type, char const *arg) {
  struct command *c = malloc(sizeof(struct command));

  c->type = type;
  c->arg = malloc(strlen(arg) + 1);
  strcpy(c->arg, arg);
  c->next = *(env->commands);
  if (OSAtomicCompareAndSwapPtr(c->next, c, (void *)(env->commands)) == false) {
    // The only thing the thread can write to commands is NULL, so we can just
    // try one more time
    c->next = NULL;
    if (OSAtomicCompareAndSwapPtr(c->next, c, (void *)(env->commands)) == false) {
      // This should never happen
      fprintf(stderr, "Unexpected error with fsevents lockless commands list\n");
    }
  }
  signal_on_pipe(env->write_command_fd);
}
Esempio n. 7
0
bool
AtomicPtr::assign(void* ptrNew, const void* const ptrOld)
{
#if defined(_OPENTHREADS_ATOMIC_USE_GCC_BUILTINS)
    return __sync_bool_compare_and_swap(&_ptr, ptrOld, ptrNew);
#elif defined(_OPENTHREADS_ATOMIC_USE_WIN32_INTERLOCKED)
    return ptrOld == InterlockedCompareExchangePointer((PVOID volatile*)&_ptr, (PVOID)ptrNew, (PVOID)ptrOld);
#elif defined(_OPENTHREADS_ATOMIC_USE_BSD_ATOMIC)
    return OSAtomicCompareAndSwapPtr((void *)ptrOld, (void *)ptrNew, (void* volatile *)&_ptr);
#else
# error This implementation should happen inline in the include file
#endif
}
Esempio n. 8
0
/**
 \brief Copy supplied RangeList to the internal RangeList and make that the valid one.
 \param inOutBuffer buffer to hold the fetched data
 \param inBufferLength length of supplied buffer in inOutBuffer
 \param inOutRangeList RangeList to hold new state
 \param outReturnedBytesCount count of bytes which are returned
 
 This method can be used to free a locally used RangeList. It can be called from any thread
 */
LockFreeQueueReturnCode LockFreeQueue::InternalizeRangeList(RangeList* inRangeList)
{
    OSMemoryBarrier();
    RangeList *oldRangeList = (RangeList*)mRangeList;
    
    if (inRangeList != oldRangeList)
    {
        // supplied range list is not the valid one --> nothing to do
        return LockFreeQueue_OK;
    }

    memcpy(&mInternalRangeList, oldRangeList, sizeof(RangeList));
    
    bool result = OSAtomicCompareAndSwapPtr(oldRangeList, &mInternalRangeList, (void* volatile*)&mRangeList);
    
    return result ? LockFreeQueue_OK : LockFreeQueue_casUnsuccessful;
}
Esempio n. 9
0
/**
 \brief Store a blob of data
 \param inBufferToStore buffer to store
 \param inBufferLength length of supplied buffer in inBufferToStore
 \param inReservedList RangeList used to reserve space for this store
 \param inOutRangeList RangeList to hold new state
 
 This method should only be called from the storing thread
 */
LockFreeQueueReturnCode     LockFreeQueue::Store(const char *inBufferToStore, unsigned long inBufferLength, RangeList* inReservedList, RangeList* inOutRangeList)
{
    if (inReservedList == inOutRangeList)
    {
        printf("can't use same RangeList!\n");
        return LockFreeQueue_sameRangeList;
    }
    
    if (inReservedList->mReservedRange.mLength != inBufferLength)
    {
        printf("sorry but you reserved a different length!\n");
        return LockFreeQueue_differentByteCountThanReserved;
    }
    
    OSMemoryBarrier();
    RangeList *oldRangeList = (RangeList *)mRangeList;
    
    if (oldRangeList)
    {
        if (!oldRangeList->mHasReserved
            || oldRangeList->mReservedRange.mLength != inReservedList->mReservedRange.mLength
            || oldRangeList->mReservedRange.mPosition != inReservedList->mReservedRange.mPosition)

        {
            printf("something is strange! (1)\n");
            return LockFreeQueue_fileABug;
        }
        
        memcpy(inOutRangeList, oldRangeList, sizeof(RangeList));
    }
    else
    {
        printf("something is strange! (We *should* have an old range list)\n");
        return LockFreeQueue_fileABug;        
    }
    
    Range firstByteRange;
    Range secondByteRange;

    RangePartsOfByteRange(&firstByteRange, &secondByteRange, &oldRangeList->mReservedRange);
    
    if (secondByteRange.mLength == 0)
    {
        memcpy(&(mDataRing[firstByteRange.mPosition]), inBufferToStore, inBufferLength);
    }
    else
    {
        memcpy(&(mDataRing[firstByteRange.mPosition]), inBufferToStore, firstByteRange.mLength);
        memcpy(&(mDataRing[secondByteRange.mPosition]), &(inBufferToStore[firstByteRange.mLength]), inBufferLength-firstByteRange.mLength);
    }

    inOutRangeList->mFullRanges[inOutRangeList->mFullRangeCount] = oldRangeList->mReservedRange;
    inOutRangeList->mFullRangeCount++;
    inOutRangeList->mReservedRange.mLength = 0;
    inOutRangeList->mReservedRange.mPosition = 0;
    inOutRangeList->mHasReserved = false;
    
    bool result = OSAtomicCompareAndSwapPtr(oldRangeList, inOutRangeList, (void* volatile*)&mRangeList);
    
    return result ? LockFreeQueue_OK : LockFreeQueue_casUnsuccessful;
}