github.com/icexin/eggos@v0.4.2-0.20220216025428-78b167e4f349/kernel/syscall_thread.go (about)

     1  package kernel
     2  
     3  import (
     4  	"runtime"
     5  	"syscall"
     6  	"unsafe"
     7  
     8  	"github.com/icexin/eggos/kernel/isyscall"
     9  	"github.com/icexin/eggos/kernel/sys"
    10  	"github.com/icexin/eggos/log"
    11  )
    12  
    13  var (
    14  	syscalltask threadptr
    15  
    16  	// pendingCall is the address of pending forward syscall
    17  	pendingCall uintptr
    18  )
    19  
    20  //go:nosplit
    21  func forwardCall(call *isyscall.Request) {
    22  	// wait syscall task fetch pendingCall
    23  	for pendingCall != 0 {
    24  		sleepon(&pendingCall)
    25  	}
    26  	pendingCall = uintptr(unsafe.Pointer(call))
    27  	// tell syscall task pendingCall is avaiable
    28  	// we can't only wakeup only one thread here
    29  	wakeup(&pendingCall, -1)
    30  
    31  	// wait on syscall task handle request
    32  	sleepon(&call.Lock)
    33  
    34  	// for debug purpose
    35  	if -call.Ret() == uintptr(isyscall.EPANIC) {
    36  		preparePanic(Mythread().tf)
    37  	}
    38  }
    39  
    40  //go:nosplit
    41  func fetchPendingCall() uintptr {
    42  	// waiting someone call forward syscall
    43  	for pendingCall == 0 {
    44  		sleepon(&pendingCall)
    45  	}
    46  	ret := pendingCall
    47  	pendingCall = 0
    48  	// wakeup one thread, pendingCall is avaiable
    49  	wakeup(&pendingCall, 1)
    50  	return ret
    51  }
    52  
    53  // runSyscallThread run in normal go code space
    54  func runSyscallThread() {
    55  	runtime.LockOSThread()
    56  	my := Mythread()
    57  	syscalltask = (threadptr)(unsafe.Pointer(my))
    58  	log.Infof("[syscall] tid:%d", my.id)
    59  	for {
    60  		callptr, _, err := syscall.Syscall(SYS_WAIT_SYSCALL, 0, 0, 0)
    61  		if err != 0 {
    62  			throw("bad SYS_WAIT_SYSCALL return")
    63  		}
    64  		call := (*isyscall.Request)(unsafe.Pointer(callptr))
    65  
    66  		no := call.NO()
    67  		handler := isyscall.GetHandler(no)
    68  		if handler == nil {
    69  			log.Errorf("[syscall] unhandled %s(%d)(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x)",
    70  				syscallName(int(no)), no,
    71  				call.Arg(0), call.Arg(1), call.Arg(2), call.Arg(3),
    72  				call.Arg(4), call.Arg(5))
    73  			call.SetErrorNO(syscall.ENOSYS)
    74  			call.Done()
    75  			continue
    76  		}
    77  		go func() {
    78  			handler(call)
    79  			var iret interface{}
    80  			ret := call.Ret()
    81  			if hasErrno(ret) {
    82  				iret = syscall.Errno(-ret)
    83  			} else {
    84  				iret = ret
    85  			}
    86  			log.Debugf("[syscall] %s(%d)(0x%x, 0x%x, 0x%x, 0x%x, 0x%x, 0x%x) = %v",
    87  				syscallName(int(no)), no,
    88  				call.Arg(0), call.Arg(1), call.Arg(2), call.Arg(3),
    89  				call.Arg(4), call.Arg(5), iret,
    90  			)
    91  			call.Done()
    92  		}()
    93  	}
    94  }
    95  
    96  func hasErrno(n uintptr) bool {
    97  	return 1<<(sys.PtrSize*8-1)&n != 0
    98  }