root/src/apps/powerstatus/DriverInterface.cpp
/*
 * Copyright 2009-2015, Haiku, Inc. All Rights Reserved.
 * Distributed under the terms of the MIT License.
 *
 * Authors:
 *              Clemens Zeidler, haiku@Clemens-Zeidler.de
 */


#include "DriverInterface.h"

#include <Autolock.h>
#include <Messenger.h>


Monitor::~Monitor()
{
}


status_t
Monitor::StartWatching(BHandler* target)
{
        if (fWatcherList.HasItem(target))
                return B_ERROR;

        fWatcherList.AddItem(target);
        return B_OK;
}


status_t
Monitor::StopWatching(BHandler* target)
{
        return fWatcherList.RemoveItem(target);
}


void
Monitor::Broadcast(uint32 message)
{
        for (int i = 0; i < fWatcherList.CountItems(); i++) {
                BMessenger messenger(fWatcherList.ItemAt(i));
                messenger.SendMessage(message);
        }
}


//      #pragma mark -


PowerStatusDriverInterface::PowerStatusDriverInterface()
        :
        fIsWatching(0),
        fWaitSem(-1),
        fThread(-1),
        fListLocker("driver list")
{
}


PowerStatusDriverInterface::~PowerStatusDriverInterface()
{
}


status_t
PowerStatusDriverInterface::StartWatching(BHandler* target)
{
        BAutolock autolock(fListLocker);

        status_t status = Monitor::StartWatching(target);
        if (status != B_OK)
                return status;

        if (fThread > 0)
                return B_OK;

        fThread = spawn_thread(&_ThreadWatchPowerFunction, "PowerStatusThread",
                B_LOW_PRIORITY, this);
        if (fThread >= 0) {
                fWaitSem = create_sem(0, "power status wait");

                atomic_set(&fIsWatching, 1);
                status = resume_thread(fThread);
        } else
                return fThread;

        if (status != B_OK && fWatcherList.CountItems() == 0) {
                atomic_set(&fIsWatching, 0);
                delete_sem(fWaitSem);

                fThread = -1;
                fWaitSem = -1;
        }

        return status;
}


status_t
PowerStatusDriverInterface::StopWatching(BHandler* target)
{
        if (fThread < 0)
                return B_BAD_VALUE;

        fListLocker.Lock();

        if (fWatcherList.CountItems() == 1) {
                fListLocker.Unlock();
                Disconnect();
        } else
                fListLocker.Unlock();

        return Monitor::StopWatching(target);
}


void
PowerStatusDriverInterface::Broadcast(uint32 message)
{
        BAutolock autolock(fListLocker);
        Monitor::Broadcast(message);
}


void
PowerStatusDriverInterface::Disconnect()
{
        if (fThread < 0)
                return;

        atomic_set(&fIsWatching, 0);
        delete_sem(fWaitSem);

        wait_for_thread(fThread, NULL);
        fThread = -1;
        fWaitSem = -1;
}


int32
PowerStatusDriverInterface::_ThreadWatchPowerFunction(void* data)
{
        PowerStatusDriverInterface* that = (PowerStatusDriverInterface*)data;
        that->_WatchPowerStatus();
        return 0;
}