예제 #1
0
        public static int DoFutex(Thread current, ref Arch.ExceptionRegisters regs, UserPtr uaddr, int op, int val, UserPtr timeoutPtr, UserPtr uaddr2, uint val3)
        {
            var cmd = op & FUTEX_CMD_MASK;
            var flags = ToFlags(op, cmd);
            timespec ts;
            ts.tv_sec = ts.tv_nsec = 0;

            // Don't care about shared mutex
            if ((flags & FLAGS_SHARED) != 0)
            {
                return DoFutexShared(current, ref regs, uaddr, op, val, timeoutPtr, uaddr2, val3);
            }

            bool hasTimeout = timeoutPtr != UserPtr.Zero;
            if (hasTimeout && timeoutPtr.Read(current, out ts) != 0)
                return -ErrorCode.EFAULT;

            switch (cmd)
            {
                case FUTEX_WAIT:
                    return Wait(current, ref regs, uaddr, flags, val, hasTimeout, ts, FUTEX_BITSET_MATCH_ANY);
                case FUTEX_WAIT_BITSET:
                    return Wait(current, ref regs, uaddr, flags, val, hasTimeout, ts, val3);
                case FUTEX_WAKE:
                    return Wake(current, uaddr, flags, val, FUTEX_BITSET_MATCH_ANY);
                case FUTEX_WAKE_BITSET:
                    return Wake(current, uaddr, flags, val, val3);
                default:
                    Arch.Console.Write("futex: unknown primitives ");
                    Arch.Console.Write(cmd);
                    Arch.Console.WriteLine();
                    return -ErrorCode.ENOSYS;
            }
        }
예제 #2
0
        // Forward the futex request to Linux helper
        private static int DoFutexShared(Thread current, ref Arch.ExceptionRegisters regs, UserPtr uaddr, int op, int val, UserPtr timeoutPtr, UserPtr uaddr2, uint val3)
        {
            // Some local test
            var cmd = op & FUTEX_CMD_MASK;
            timespec ts = new timespec();

            bool hasTimeout = timeoutPtr != UserPtr.Zero;
            if (hasTimeout && timeoutPtr.Read(current, out ts) != 0)
                return -ErrorCode.EFAULT;

            if (cmd == FUTEX_WAIT || cmd == FUTEX_WAIT_BITSET)
            {
                int old_val;
                if (uaddr.Read(current, out old_val) != 0)
                    return -ErrorCode.EFAULT;

                if (old_val != val)
                    return -ErrorCode.EWOULDBLOCK;

                var bitset = cmd == FUTEX_WAIT ? FUTEX_BITSET_MATCH_ANY : val3;
                var shadowAddr = FindShadowAddr(current, uaddr);

                if (shadowAddr == Pointer.Zero)
                {
                    Arch.Console.WriteLine("FutexShared: Don't know how to deal with shared_wait");
                    return 0;
                }

                var futex_entry = new FutexCompletionEntry(current, uaddr, bitset);

                Arch.IPCStubs.linux_sys_futex_wait(current.Parent.helperPid, current.impl._value.thread._value, op, shadowAddr, val, ts, bitset);

                Globals.CompletionQueue.Enqueue(futex_entry);
                current.SaveState(ref regs);
                current.AsyncReturn = true;
                return 0;
            }
            else if (cmd == FUTEX_WAKE || cmd == FUTEX_WAKE_BITSET)
            {
                var bitset = cmd == FUTEX_WAKE ? FUTEX_BITSET_MATCH_ANY : val3;
                if (bitset == 0)
                    return -ErrorCode.EINVAL;

                var shadowAddr = FindShadowAddr(current, uaddr);
                if (shadowAddr == Pointer.Zero)
                {
                    Arch.Console.WriteLine("FutexShared: Don't know how to deal with shared_wake");
                    return 0;
                }

                var c = new BridgeCompletion(current, new ByteBufferRef());

                Arch.IPCStubs.linux_sys_futex_wake(current.Parent.helperPid, current.impl._value.thread._value, op, shadowAddr, bitset);

                Globals.CompletionQueue.Enqueue(c);
                current.SaveState(ref regs);
                current.AsyncReturn = true;

                return 0;
            }

            return 0;
        }
예제 #3
0
        private static int Wait(Thread current, ref Arch.ExceptionRegisters regs, UserPtr uaddr, int flags, int val, bool hasTimeout, timespec ts, uint bitset)
        {
            int old_val;
            if (uaddr.Read(current, out old_val) != 0)
                return -ErrorCode.EFAULT;

            if (old_val != val)
                return -ErrorCode.EWOULDBLOCK;

            //Arch.Console.Write("wait: addr=");
            //Arch.Console.Write(uaddr.Value.ToUInt32());
            //Arch.Console.Write(" thr=");
            //Arch.Console.Write(current.Tid);
            //Arch.Console.WriteLine();

            TimerQueueNode node;
            var futex_entry = new FutexCompletionEntry(current, uaddr, bitset);
            Globals.FutexLists.InsertAtTail(futex_entry);

            if (hasTimeout)
            {
                node = Globals.TimeoutQueue.Enqueue(ts.ToMilliseconds(), current);
                futex_entry.timeoutNode = node;
            }

            Globals.CompletionQueue.Enqueue(futex_entry);
            current.SaveState(ref regs);
            current.AsyncReturn = true;
            return 0;
        }