Skip to content

Latest commit

 

History

History
365 lines (211 loc) · 20.6 KB

defs_linux_riscv64.go.md

File metadata and controls

365 lines (211 loc) · 20.6 KB

File: defs_linux_riscv64.go

defs_linux_riscv64.go是Go语言的运行时系统(runtime)的一个源代码文件,用于定义在Linux系统上运行的RISC-V 64位处理器架构的常量和变量。该文件提供了与操作系统、内存和CPU体系结构相关的信息,在Go程序执行期间起着关键的作用。

具体来说,defs_linux_riscv64.go文件定义了以下常量和变量:

  1. OS、ARCH和StackMin:分别表示运行时所在的操作系统、CPU架构和栈的最小大小。

  2. 系统调用数字常量:对于Linux系统而言,这些常量可以在系统调用接口中用于表明不同类型的调用。

  3. Erlibc:表示运行时是否使用了外部的C库,用于链接C程序库。

  4. 架构相关的类型和变量:包括处理器指令集、寄存器等。

  5. 与堆栈相关的变量:堆栈指针、堆栈大小等。

通过定义这些常量和变量,defs_linux_riscv64.go文件为运行时系统提供了必要的信息,使得系统能够正确地进行调度、内存管理和系统调用等基础操作。


Structs:

timespec

在Go语言运行时的defs_linux_riscv64.go文件中,timespec是一个结构体,用于表示时间值。它包含两个字段:秒(tv_sec)和纳秒(tv_nsec),这两个字段合起来表示一个精确到纳秒级的时间值。

timespec结构体在系统调用中经常用于处理和计算时间,例如在IO操作、套接字通信、定时器等系统操作中,都需要用到时间参数。因此,这个结构体在操作系统中具有重要的作用。

在Go语言的运行时中,timespec结构体被用于实现定时器、调度器和其他与时间相关的功能。例如,在定时器中,可以使用timespec结构体来表示定时器的间隔时间和触发时间。而在调度器中,也可以使用timespec结构体来计算和判断线程的调度时间和优先级。

总之,timespec结构体在操作系统和编程语言中都具有重要的作用,它为处理时间提供了简单、高效和可重用的方法。

timeval

在Go语言中,timeval结构体是用来表示时间值的数据类型,在defs_linux_riscv64.go这个文件中,它被定义为:

type timeval struct {
        tv_sec  int64
        tv_usec int64
}

其中,tv_sec表示秒数,tv_usec表示微秒数,它们的值会根据系统的时钟和调度来变化。

在Linux系统中,timeval结构体通常用于获取系统当前时间、计算时间差、进行延时等操作。在Go语言中,time包提供了很多与时间操作相关的函数和类型,如time.Now()可以获取当前时间,time.Duration表示时间段等,这些都与timeval结构体有关。

在defs_linux_riscv64.go这个文件中,timeval结构体被用于实现定时器和时间轮相关的功能。具体来说,在Linux系统中,定时器是一种可以在指定时间后自动触发一个事件的机制。而时间轮则是用于管理定时器的一种算法,通过将所有的定时器按照剩余时间分成不同的轮,从而实现对定时器的高效管理。在Go语言中,这些功能都由time包提供,timeval结构体被用于保存和计算定时器的时间值。

sigactiont

在Go语言运行时的defs_linux_riscv64.go文件中,sigactiont是一个结构体类型,用于设置和传递信号处理器的信息。

在Linux系统中,进程在接收到信号时必须要有一个信号处理器来处理该信号。sigactiont结构体用于描述信号处理器的函数指针和一些标志位,提供了对信号处理的配置和控制。

具体来说,sigactiont结构体包括以下字段:

  • sa_handler: 信号处理函数的地址,处理器会在接收到该信号时调用该函数;
  • sa_flags: 用于指定信号处理的一些特定标志,如SA_SIGINFO表示需要传递附加的信号信息给信号处理函数;
  • sa_restorer: 用于指定恢复函数的地址,在该信号处理函数执行完之后,将会调用该函数对进程进行恢复。

通过使用sigactiont结构体,我们可以设置和注册信号处理函数,处理并响应进程中的各种信号,保证程序能够正常运行。

siginfoFields

在Go语言的运行时中,siginfoFields这个结构体定义了信号处理函数在接收到信号时应该传递的信息。它是一个包含多个字段的结构体,每个字段都对应着一个信号处理函数需要的信息。

这些字段包括了:

  • Signo: 信号的编号,比如SIGINT;
  • Errno: 发生错误时的错误码,如果没有错误则为0;
  • Code: 信号导致的进程状态变化的代码,比如进入暂停状态;
  • PID: 产生信号的进程的ID;
  • UID, GID: 信号产生时的用户ID和组ID;
  • Timer: 定时信号的时间;
  • FD: 文件描述符;
  • Addr: 内存地址;
  • Addr_lsb: 地址的最低有效位;
  • Lower: 信号传递的辅助数据的下界;
  • Upper: 信号传递的辅助数据的上界。

这些字段提供了信号处理函数必要的信息,以便它可以根据信号的类型和属性进行特定的操作,比如打印日志、修改进程状态或清理资源。在Go语言的运行时中,这些信息存储在siginfoFields结构体中,并且由操作系统负责将其传递给信号处理函数。

siginfo

在Go语言中,defs_linux_riscv64.go这个文件定义了在RISC-V 64位Linux系统上使用的一些常量和结构体。其中,siginfo结构体用于捕获和传递信号相关的信息。

具体来说,siginfo结构体包含以下字段:

  1. si_signo:表示产生信号的数字编号
  2. si_errno:表示与信号相关的错误代码
  3. si_code:表示信号的来源和类型
  4. si_pid:表示发送信号的进程ID
  5. si_uid:表示发送信号的用户ID
  6. si_status:表示进程退出时的状态值
  7. si_utime:表示进程运行的累计用户CPU时间
  8. si_stime:表示进程运行的累计系统CPU时间
  9. si_value:表示信号的附加值
  10. si_addr:表示信号产生时的内存地址
  11. si_band:表示信号的附加事件

这些信息可以通过siginfo结构体传递给信号处理函数,并由该函数进行处理或记录。例如,程序中可以根据si_signo字段判断收到的是哪种信号,si_pid和si_uid字段可以记录信号来源,si_status字段可以记录进程退出的状态值等。

总的来说,siginfo结构体提供了一个容器,用于在进程间传递有关信号信息的数据,并帮助开发人员更好地了解和处理信号。

itimerspec

在Go语言中,defs_linux_riscv64.go文件定义了一些底层的系统结构体和常量,用于在RISC-V 64位Linux系统上运行Go程序。其中,itimerspec是一个结构体,用于指定定时器的时间间隔。

在RISC-V 64位Linux系统中,定时器是一个重要的系统组件,用于定期触发某些操作,例如定时器中断、进程调度等等。itimerspec结构体定义了两个成员变量:it_intervalit_value。其中,it_interval表示定时器的循环间隔时间,即定时器触发后,再次触发之间的时间间隔。it_value表示定时器的首次触发时间,即从当前时间开始,第一次触发定时器的时间。

在Go语言中,我们可以利用itimerspec结构体来设置定时器的时间间隔。例如,下面的代码会创建一个定时器,每隔1秒钟触发一次:

import (
	"syscall"
	"time"
)

func main() {
	var timer syscall.Itimer = syscall.Itimer{
		Value: syscall.Timespec{
			Sec:  1,
			Nsec: 0,
		},
		Interval: syscall.Timespec{
			Sec:  1,
			Nsec: 0,
		},
	}
	syscall.Setitimer(syscall.ITIMER_REAL, &timer, nil)
	for {
		time.Sleep(time.Second)
	}
}

上述代码首先创建一个名为timersyscall.Itimer对象,其中ValueInterval成员变量都被设置为1秒钟。接着,调用syscall.Setitimer函数来启动定时器,并制定定时器类型为ITIMER_REAL,表示定时器是一个真实时间定时器。最后,程序进入一个无限循环,每隔1秒钟输出一条提示信息。

总之,itimerspec结构体是在RISC-V 64位Linux系统上控制定时器的重要工具,可以帮助我们实现各种高效的时间控制功能。

itimerval

在go/src/runtime中,defs_linux_riscv64.go文件定义了一些在RISC-V 64位Linux系统中用到的底层数据结构和常量。其中,itimerval结构体表示一个定时器值结构。具体来说,itimerval结构体中包含两个成员:

type itimerval struct { it_interval timeval it_value timeval }

其中,timeval也是一个结构体:

type timeval struct { tv_sec int64 tv_usec int64 }

it_interval成员指定定时器重复周期,单位是微秒;it_value成员指定定时器开始倒计时的初始值,同样以微秒为单位。此结构体是Linux系统中设置定时器的必要参数,它用于支持虚拟时钟功能,比如在Go语言中使用的time包。

在运行时中,定时器可以用于多个用途,例如可以帮助管理运行时的调度器,或者用于处理定期运行的任务。itimerval结构体定义了定时器的参数,提供了一种方便的方式来设置定时器和检查定时器状态。

sigeventFields

在Go的运行时环境中,sigeventFields结构体用于定义一个事件通知对象,该对象可以使用SIGEV_SIGNAL信号代替传统的Unix信号通知方式。sigeventFields结构体中包含以下字段:

  • value:通知的值。
  • signo:通知的信号。
  • notify:通知的方式,通常为SIGEV_SIGNAL。

通过定义sigeventFields结构体可以直接使用信号作为事件通知的方式,可以方便地与Unix信号处理机制进行交互。在Go语言中,通过使用sigeventFields结构体定义每个事件通知对象,可以方便地与Linux RISC-V64平台上的操作系统进行交互。

sigevent

在Linux下的RISC-V 64位架构中,defs_linux_riscv64.go文件定义了一系列运行时相关的常量、类型和数据结构,而其中sigevent结构体用于描述异步信号事件。

异步信号事件是一种当指定的信号到达进程时,内核会自动生成一个事件,通知进程相关的异步I/O操作已完成或者出现了某些情况。sigevent结构体定义了被通知的事件的相关信息,包括事件的类型、处理方式、数据等。

sigevent结构体包括以下几个字段:

  • Value:用于传输事件相关的数据,类型为int64;
  • Signo:需要异步通知的信号编号,类型为int32;
  • Notify:事件处理方式的标志,类型为uint32;
  • _padding:对齐用的空字段,避免使用时出现不必要的对齐问题。

在异步I/O操作中通常需要使用到sigevent结构体,通过向操作系统注册一个异步I/O事件,让操作系统在特定的条件下通知进程,当异步I/O操作完成或出现错误时,操作系统就会生成一个信号并通知进程相应的事件已发生,进而处理事件。

总的来说,sigevent结构体描述了需要通知的异步信号事件的相关信息,用于操作系统和进程之间的通信。

user_regs_struct

在Linux系统中,user_regs_struct结构体用于保存用户空间程序的CPU寄存器信息。这个结构体可以在系统调用时被内核修改以保存用户程序的状态,在进程切换时,这个结构体也会被用来保存原进程的CPU状态以及加载新进程的CPU状态。

具体来说,该结构体包含64位RISC-V CPU中通用寄存器和特殊寄存器的值。例如,x0是零寄存器,x1-x31是通用寄存器,pc寄存器存储程序计数器的值,而特殊寄存器包括syscall、sepc、sstatus等。

在Go语言中,定义了Linux下RISC-V 64位架构相关的类型和常量,包括了user_regs_struct结构体,以便在实现golang的系统调用时可以更好地控制其CPU寄存器的状态。因此,defs_linux_riscv64.go文件中的user_regs_struct结构体和其它一些定义和声明对于Go语言在RISC-V 64位平台上实现系统调用、程序执行和处理器状态的管理都非常关键。

user_fpregs_struct

在RISC-V 64位架构中,user_fpregs_struct(用户浮点寄存器结构体)是用来存储用户进程的浮点寄存器的数据结构。这个结构体中包含一个64位的寄存器数组,用于保存用户程序中FP寄存器的值。

在操作系统内核中,当一个用户进程被调度执行时,内核会使用这个结构体来保存用户进程当前的浮点寄存器状态。当用户进程再次被调度执行时,内核会从这个结构体中读取浮点寄存器的值,并载入到浮点寄存器中,以恢复用户进程的执行状态。

这个结构体的具体定义和使用在defs_linux_riscv64.go文件中,其代码如下:

type user_fpregs_struct struct { fregs [32]uint64 // FP寄存器数组,共32个寄存器 }

可以看出,这个结构体中只有一个数组成员fregs,其长度为32,表示64位RISC-V架构中的32个浮点寄存器。在内核中使用这个结构体时,操作系统会将其作为浮点寄存器状态的载体,以便保存和恢复用户进程的浮点寄存器值。

usigset

在Linux上,usigset结构体是用于表示一组信号的集合。其定义如下:

type usigset [16]uint64

这里的uint64代表一个64位的位图(bitmap),每一位对应一个信号,如果该位被置为1,则表示这个信号属于该信号集合。而usigset[0]表示了信号063的集合,usigset[1]表示了信号64127的集合,以此类推。

该结构体的作用是在Go语言中实现信号处理。例如,在Go语言中,我们可以使用os/signal包来处理信号,可以监听某个信号,也可以忽略某个信号。在内部实现中,使用了usigset结构体来表示信号的集合,通过调用syscall包中的系统调用来注册信号处理函数。当一个信号被触发时,内核会将该信号从信号集合中清除,然后执行相应的信号处理函数。

因此,usigset结构体在Go语言中实现信号处理的过程中起到了关键作用。

sigcontext

在运行时环境中,sigcontext是用于存储捕获信号时CPU寄存器状态的结构体。在defs_linux_riscv64.go中,这个结构体用于定义RISC-V 64位架构下的sigcontext结构。该结构体包含了寄存器的值以及一些与处理器状态相关的其他信息,如程序计数器、陷阱码、用户态/内核态标志等。

当进程接收到信号时,信号处理程序通过sigcontext结构体可以获取到当前进程的寄存器状态,从而可以确定进程接收信号的上下文。sigcontext还可用于设置或修改进程的寄存器状态,在某些情况下,可能需要在信号处理程序中修改进程的寄存器值。

值得说明的是,不同架构下的sigcontext结构体定义可能会有所不同,因为不同架构下处理器的寄存器集合和寄存器状态保存方式都有所不同。在RISC-V 64位架构下,defs_linux_riscv64.go中定义了如下sigcontext结构体:

type sigcontext struct { faultaddr uint64 regs [32]uint64 fltregs [32]uint64 fir uint64 fcsr uint64 __reserved [2]uint64 // ... }

其中,regs数组和fltregs数组分别表示整数寄存器和浮点数寄存器的值,fir表示陷阱返回寄存器,fcsr表示浮点控制/状态寄存器。由于RISC-V架构采用统一的寄存器编址模型,因此regs和fltregs数组的大小都为32,每个元素都是64位长的寄存器。在使用sigcontext结构体时,需要注意它的大小和对齐方式,以保证正确的寄存器状态被保存和恢复。

stackt

defs_linux_riscv64.go文件是Go语言运行时的一个实现文件,stackt是其中一个结构体,主要用于记录系统栈的信息以及分配它时需要的参数。

该结构体的定义如下:

type stackt struct {
	stack   unsafe.Pointer // stack memory
	stackHi uintptr        // end of stack memory
	g0      *g             // goroutine with scheduling stack
}

其中,stack字段代表系统栈的起始位置,stackHi字段代表系统栈的结束位置,g0字段是一个指针类型,指向拥有调度栈的goroutine。

stackt结构体用于描述系统栈的内存信息,它包含了系统栈的起始地址和结束地址,以及与系统栈相关的goroutine。当我们需要为goroutine分配栈时,需要先创建一个stackt结构体,然后根据相应的参数进行初始化,最后将这个结构体返回给调用方。

总的来说,stackt结构体起到了记录系统栈信息和提供分配内存的功能,为运行时系统提供必要的支持。

ucontext

在go/src/runtime/defs_linux_riscv64.go这个文件中,ucontext这个结构体定义了RISC-V架构下的上下文保存数据结构,是在进程或线程转换时用于保存CPU寄存器及其状态的数据结构。

具体来说,ucontext包含了两个部分:

  1. IRQ上下文保存部分,保存了处理器执行转移时的CPU状态,如下所示:
type mcontext struct {
  //...
  gregs     [NGREG]uint64
  csrs      [NCSR]uint64
}

type ucontext struct {
  uc_flags    uint64
  uc_link     *ucontext
  uc_stack    stackt
  uc_mcontext mcontext
  __reserved  [8]uint64
}

其中,gregs数组保存了所有通用寄存器的值(R0~R31),csrs数组保存了所有特殊控制寄存器的值(如sstatus、sbadaddr等)。

  1. 堆栈信息上下文保存部分,保存了运行环境的信息,如下所示:
type stackt struct {
  ss_sp    *uint8
  ss_flags int32
  ss_size  uintptr
}

其中,ss_sp指向一个堆栈区域,ss_size是这个堆栈区域的大小,ss_flags是堆栈的属性(例如是否可读写等)。

ucontext结构体主要用于线程的切换,当需要切换执行上下文时,可以通过保存和恢复ucontext结构体中的内容达到快速切换上下文的目的。RISC-V架构的处理器提供了许多特殊的控制寄存器,用于控制中断、异常、页表等重要机制,保存和恢复这些控制寄存器的值是非常重要的。ucontext结构体中的mcontext部分就是用来保存这些控制寄存器的值的,这样在线程切换时可以快速恢复这些值,从而保证程序的正确执行。

总之,ucontext是一个非常重要的数据结构,它用于在操作系统中保存线程/进程的上下文信息,方便快速地在不同线程之间进行切换。

Functions:

setNsec

setNsec函数是一个将时间戳纳秒值设为调度器全局时间的函数,它的作用是用于设置调度器的全局时间,以便进行调度。

在Golang中,有很多地方需要知道当前的时间,例如定时器,调度器和GC。而为了保证所有的时间都是精确的,Golang会在每一个操作系统线程中记录一个时间戳纳秒值。这些时间戳纳秒值可以在不同的线程之间进行传递和比较。当调度器需要知道当前时间时,它会调用setNsec函数获取时间戳纳秒值,并将它保存到调度器的全局变量中。

实际上,setNsec函数并不是直接获取系统时间,而是根据当前的系统时间和调度器启动时间计算得到时间戳纳秒值。这样做的好处在于,可以排除系统时间和调度器启动时间之间的误差,从而保证了时间的精度和准确性。

总之,setNsec函数是Golang调度器中非常重要的一个函数,它用于设置调度器的全局时间,以便进行调度和管理。

set_usec

在Go语言的运行时环境(runtime)中,defs_linux_riscv64.go文件定义了一些跨平台的常数和函数,以便在Linux RISC-V 64位系统上运行Go程序。

set_usec函数的作用是将调度时间片(调度器时间量)从纳秒转换为微秒单位。具体地说,它将每次运行的时间间隔(以纳秒为单位)除以1000,得到一个以微秒为单位的值,并将其存储在全局变量schedtick中。schedtick变量表示内核调度的时间片长度,即每个goroutine在系统上运行的时间间隔。

在Go语言中,调度器使用两种方法来控制goroutine的执行:时间分片和协作式调度。时间片是使用分时调度机制来实现的,这意味着每个goroutine被分配一个确定的时间片长度,当时间片结束时,goroutine将被挂起并等待下一个时间片。set_usec函数的作用是将时间片长度转换为微秒单位,以便调度器能够更精确地控制goroutine的执行。

总之,set_usec函数对于Go语言运行时在Linux RISC-V 64位系统上实现时间分片调度机制是非常重要的,它将每次运行的时间间隔转换为适当的微秒单位,并存储在全局变量schedtick中,以便调度器能够更好地控制goroutine的执行。