#ifndef __KERNEL_AUTOSPINLOCK_H
#define __KERNEL_AUTOSPINLOCK_H

#include <sys/types.h>
#include <new.h>
#include <cpp/Uncopyable.h>
#include <kernel/Spinlock.h>
#include <kernel/Thread.h>

namespace OS { 
namespace Kernel {

class AutoSpinlock : private Uncopyable {
  public:
	AutoSpinlock(Spinlock &lock) 
		: mPreemptRef(),
		mSpinlockRef(lock) { }
	~AutoSpinlock() { }

	void Release() {
		mSpinlockRef.Release();
		mPreemptRef.Release();
	}

  private:
	ThreadPreemptRef mPreemptRef; // will acquire a ref to the thread's preemption count and release it when the object goes out of scope
	SpinlockRef mSpinlockRef; // will acquire a spinlock ref and release when the object goes out of scope
};

// special case of a conditional autospinlock (in case you sometimes dont want to grab it, but still want the auto releasing capabaility)
class ConditionalAutoSpinlock : private Uncopyable {
  public:
	ConditionalAutoSpinlock(Spinlock &lock, bool acquire) : mASL(NULL) {
		if (acquire)
			mASL = new(mASLStorage) AutoSpinlock(lock);
	}
	~ConditionalAutoSpinlock() {
		if (mASL)
			mASL->~AutoSpinlock();
	}

	void Release() {
		if (mASL)
			mASL->Release();
	}

  private:
	AutoSpinlock *mASL;
	uint8_t mASLStorage[sizeof(AutoSpinlock)];
};

}} // namespace OS::Kernel

#endif
