public int sceKernelPollSema(CpuThreadState CpuThreadState, SemaphoreId SemaphoreId, int Signal)
        {
            var Semaphore = GetSemaphoreById(SemaphoreId);
            if (Signal <= 0) throw(new SceKernelException(SceKernelErrors.ERROR_KERNEL_ILLEGAL_COUNT));
            if (Semaphore.CurrentCount - Signal < 0)
            {
                //ThreadManager.Reschedule();
                CpuThreadState.Yield();
                throw (new SceKernelException(SceKernelErrors.ERROR_KERNEL_SEMA_ZERO));
            }
            Semaphore.IncrementCount(-Signal);
            //throw(new NotImplementedException());
            return 0;
            /*
            try {
                PspSemaphore pspSemaphore = uniqueIdFactory.get!PspSemaphore(semaid);

                if (pspSemaphore.info.currentCount - signal < 0) return SceKernelErrors.ERROR_KERNEL_SEMA_ZERO;

                pspSemaphore.info.currentCount -= signal;
                return 0;
            } catch (UniqueIdNotFoundException) {
                return SceKernelErrors.ERROR_KERNEL_NOT_FOUND_SEMAPHORE;
            }
            */
        }
        //[HlePspNotImplemented]
        public int sceKernelPollSema(CpuThreadState CpuThreadState, SemaphoreId SemaphoreId, int Signal)
        {
            var Semaphore = GetSemaphoreById(SemaphoreId);

            if (Signal <= 0)
            {
                throw new SceKernelException(SceKernelErrors.ERROR_KERNEL_ILLEGAL_COUNT);
            }
            if (Signal > Semaphore.CurrentCount)
            {
                //ThreadManager.Reschedule();
                //CpuThreadState.Yield();
                throw new SceKernelException(SceKernelErrors.ERROR_KERNEL_SEMA_ZERO);
                //return 0;
            }
            Semaphore.IncrementCount(-Signal);
            //throw(new NotImplementedException());
            return(0);

            /*
             * try {
             *  PspSemaphore pspSemaphore = uniqueIdFactory.get!PspSemaphore(semaid);
             *
             *  if (pspSemaphore.info.currentCount - signal < 0) return SceKernelErrors.ERROR_KERNEL_SEMA_ZERO;
             *
             *  pspSemaphore.info.currentCount -= signal;
             *  return 0;
             * } catch (UniqueIdNotFoundException) {
             *  return SceKernelErrors.ERROR_KERNEL_NOT_FOUND_SEMAPHORE;
             * }
             */
        }
        private int _sceKernelWaitSemaCB(SemaphoreId SemaphoreId, int Signal, uint *Timeout, bool HandleCallbacks)
        {
            var  CurrentThread = ThreadManager.Current;
            var  Semaphore     = GetSemaphoreById(SemaphoreId);
            bool TimedOut      = false;

            CurrentThread.SetWaitAndPrepareWakeUp(HleThread.WaitType.Semaphore,
                                                  $"sceKernelWaitSema('{Semaphore.Name}')", Semaphore, WakeUpCallback =>
            {
                PspRtc.RegisterTimeout(Timeout, () =>
                {
                    TimedOut = true;
                    WakeUpCallback();
                });

                Semaphore.WaitThread(CurrentThread, () =>
                {
                    WakeUpCallback();
                    //ThreadManager.ScheduleNext(CurrentThread);
                }, Signal);
            }, HandleCallbacks: HandleCallbacks);

            if (TimedOut)
            {
                throw new SceKernelException(SceKernelErrors.ERROR_KERNEL_WAIT_TIMEOUT);
            }

            return(0);
        }
        public int sceKernelReferSemaStatus(SemaphoreId SemaphoreId, SceKernelSemaInfo *SceKernelSemaInfo)
        {
            var HleSemaphore = GetSemaphoreById(SemaphoreId);

            *SceKernelSemaInfo = HleSemaphore.SceKernelSemaInfo;
            return(0);
        }
		public int sceKernelSignalSema(CpuThreadState CpuThreadState, SemaphoreId SemaphoreId, int Signal)
		{
			//Console.Error.WriteLine("sceKernelSignalSema!");
			var HleSemaphore = GetSemaphoreById(SemaphoreId);
			if (HleSemaphore.IncrementCount(Signal) > 0)
			{
				CpuThreadState.Yield();
			}
			return 0;
		}
        public int sceKernelDeleteSema(CpuThreadState CpuThreadState, SemaphoreId SemaphoreId)
        {
            var HleSemaphore = GetSemaphoreById(SemaphoreId);
            SemaphoreManager.Semaphores.Remove((int)SemaphoreId);
            if (HleSemaphore.IncrementCount(HleSemaphore.SceKernelSemaInfo.MaximumCount) > 0)
            {
                CpuThreadState.Yield();
            }

            return 0;
        }
		HleSemaphore GetSemaphoreById(SemaphoreId SemaphoreId)
		{
			try
			{
				return SemaphoreManager.Semaphores.Get((int)SemaphoreId);
			}
			catch (KeyNotFoundException)
			{
				throw (new SceKernelException(SceKernelErrors.ERROR_KERNEL_NOT_FOUND_SEMAPHORE));
			}
		}
        public int sceKernelSignalSema(CpuThreadState CpuThreadState, SemaphoreId SemaphoreId, int Signal)
        {
            //Console.Error.WriteLine("sceKernelSignalSema!");
            var HleSemaphore = GetSemaphoreById(SemaphoreId);

            if (HleSemaphore.IncrementCount(Signal) > 0)
            {
                CpuThreadState.Yield();
            }
            return(0);
        }
 HleSemaphore GetSemaphoreById(SemaphoreId SemaphoreId)
 {
     try
     {
         return(SemaphoreManager.Semaphores.Get((int)SemaphoreId));
     }
     catch (KeyNotFoundException)
     {
         throw (new SceKernelException(SceKernelErrors.ERROR_KERNEL_NOT_FOUND_SEMAPHORE));
     }
 }
        public int sceKernelDeleteSema(CpuThreadState CpuThreadState, SemaphoreId SemaphoreId)
        {
            var HleSemaphore = GetSemaphoreById(SemaphoreId);

            SemaphoreManager.Semaphores.Remove((int)SemaphoreId);
            if (HleSemaphore.IncrementCount(HleSemaphore.SceKernelSemaInfo.MaximumCount) > 0)
            {
                CpuThreadState.Yield();
            }

            return(0);
        }
        private int _sceKernelWaitSemaCB(SemaphoreId SemaphoreId, int Signal, uint *Timeout, bool HandleCallbacks)
        {
            var CurrentThread = HleState.ThreadManager.Current;
            var Semaphore     = GetSemaphoreById(SemaphoreId);

            CurrentThread.SetWaitAndPrepareWakeUp(HleThread.WaitType.Semaphore, "sceKernelWaitSema", WakeUpCallback =>
            {
                Semaphore.WaitThread(CurrentThread, () =>
                {
                    WakeUpCallback();
                    HleState.ThreadManager.ScheduleNext(CurrentThread);
                }, Signal);
            }, HandleCallbacks: HandleCallbacks);

            return(0);
        }
        public int sceKernelPollSema(SemaphoreId SemaphoreId, int Signal)
        {
            throw(new NotImplementedException());
            /*
            if (signal <= 0) return SceKernelErrors.ERROR_KERNEL_ILLEGAL_COUNT;

            try {
                PspSemaphore pspSemaphore = uniqueIdFactory.get!PspSemaphore(semaid);

                if (pspSemaphore.info.currentCount - signal < 0) return SceKernelErrors.ERROR_KERNEL_SEMA_ZERO;

                pspSemaphore.info.currentCount -= signal;
                return 0;
            } catch (UniqueIdNotFoundException) {
                return SceKernelErrors.ERROR_KERNEL_NOT_FOUND_SEMAPHORE;
            }
            */
        }
        public int sceKernelPollSema(SemaphoreId SemaphoreId, int Signal)
        {
            throw(new NotImplementedException());

            /*
             * if (signal <= 0) return SceKernelErrors.ERROR_KERNEL_ILLEGAL_COUNT;
             *
             * try {
             *      PspSemaphore pspSemaphore = uniqueIdFactory.get!PspSemaphore(semaid);
             *
             *      if (pspSemaphore.info.currentCount - signal < 0) return SceKernelErrors.ERROR_KERNEL_SEMA_ZERO;
             *
             *      pspSemaphore.info.currentCount -= signal;
             *      return 0;
             * } catch (UniqueIdNotFoundException) {
             *      return SceKernelErrors.ERROR_KERNEL_NOT_FOUND_SEMAPHORE;
             * }
             */
        }
        private int _sceKernelWaitSemaCB(SemaphoreId SemaphoreId, int Signal, uint* Timeout, bool HandleCallbacks)
        {
            var CurrentThread = ThreadManager.Current;
            var Semaphore = GetSemaphoreById(SemaphoreId);
            bool TimedOut = false;

            CurrentThread.SetWaitAndPrepareWakeUp(HleThread.WaitType.Semaphore, "sceKernelWaitSema", Semaphore, WakeUpCallback =>
            {
                PspRtc.RegisterTimeout(Timeout, () => { TimedOut = true; WakeUpCallback(); });

                Semaphore.WaitThread(CurrentThread, () =>
                {
                    WakeUpCallback();
                    ThreadManager.ScheduleNext(CurrentThread);
                }, Signal);
            }, HandleCallbacks: HandleCallbacks);

            if (TimedOut)
            {
                throw (new SceKernelException(SceKernelErrors.ERROR_KERNEL_WAIT_TIMEOUT));
            }

            return 0;
        }
 public int sceKernelWaitSemaCB(SemaphoreId SemaphoreId, int Signal, uint* Timeout)
 {
     return _sceKernelWaitSemaCB(SemaphoreId, Signal, Timeout, HandleCallbacks: true);
 }
 public int sceKernelReferSemaStatus(SemaphoreId SemaphoreId, SceKernelSemaInfo* SceKernelSemaInfo)
 {
     var HleSemaphore = GetSemaphoreById(SemaphoreId);
     *SceKernelSemaInfo = HleSemaphore.SceKernelSemaInfo;
     return 0;
 }
 public int sceKernelWaitSemaCB(SemaphoreId SemaphoreId, int Signal, uint *Timeout)
 {
     return(_sceKernelWaitSemaCB(SemaphoreId, Signal, Timeout, HandleCallbacks: true));
 }
        private int _sceKernelWaitSemaCB(SemaphoreId SemaphoreId, int Signal, uint* Timeout, bool HandleCallbacks)
        {
            var CurrentThread = HleState.ThreadManager.Current;
            var Semaphore = GetSemaphoreById(SemaphoreId);

            CurrentThread.SetWaitAndPrepareWakeUp(HleThread.WaitType.Semaphore, "sceKernelWaitSema", WakeUpCallback =>
            {
                Semaphore.WaitThread(CurrentThread, () =>
                {
                    WakeUpCallback();
                    HleState.ThreadManager.ScheduleNext(CurrentThread);
                }, Signal);
            }, HandleCallbacks: HandleCallbacks);

            return 0;
        }