github.com/arnodel/golua@v0.0.0-20230215163904-e0b5347eaaa1/runtime/runtimecontext.go (about)

     1  package runtime
     2  
     3  // RuntimeContextDef contains the data necessary to create an new runtime context.
     4  type RuntimeContextDef struct {
     5  	HardLimits     RuntimeResources
     6  	SoftLimits     RuntimeResources
     7  	RequiredFlags  ComplianceFlags
     8  	MessageHandler Callable
     9  	GCPolicy
    10  }
    11  
    12  // RuntimeContext is an interface implemented by Runtime.RuntimeContext().  It
    13  // provides a public interface for the runtime context to be used by e.g.
    14  // libraries (e.g. the runtime package).
    15  type RuntimeContext interface {
    16  	HardLimits() RuntimeResources
    17  	SoftLimits() RuntimeResources
    18  	UsedResources() RuntimeResources
    19  
    20  	Status() RuntimeContextStatus
    21  	Parent() RuntimeContext
    22  
    23  	RequiredFlags() ComplianceFlags
    24  
    25  	SetStopLevel(StopLevel)
    26  	Due() bool
    27  
    28  	GCPolicy() GCPolicy
    29  }
    30  
    31  type StopLevel uint8
    32  
    33  const (
    34  	SoftStop StopLevel = 1 << iota // Forces the context to be due
    35  	HardStop                       // Forces the context to terminate
    36  )
    37  
    38  // A ContextTerminationError is an error reserved for when the runtime context
    39  // should be terminated immediately.
    40  type ContextTerminationError struct {
    41  	message string
    42  }
    43  
    44  var _ error = ContextTerminationError{}
    45  
    46  // Error string for a ContextTerminationError
    47  func (e ContextTerminationError) Error() string {
    48  	return e.message
    49  }
    50  
    51  // RuntimeContextStatus describes the status of a context
    52  type RuntimeContextStatus uint16
    53  
    54  const (
    55  	StatusLive   RuntimeContextStatus = iota // currently executing
    56  	StatusDone                               // finished successfully (no error)
    57  	StatusError                              // finished with a Lua error
    58  	StatusKilled                             // terminated (either by user or because hard limits were reached)
    59  )
    60  
    61  const (
    62  	liveStatusString   = "live"
    63  	doneStatusString   = "done"
    64  	errorStatusString  = "error"
    65  	killedStatusString = "killed"
    66  )
    67  
    68  func (s RuntimeContextStatus) String() string {
    69  	switch s {
    70  	case StatusLive:
    71  		return liveStatusString
    72  	case StatusDone:
    73  		return doneStatusString
    74  	case StatusError:
    75  		return errorStatusString
    76  	case StatusKilled:
    77  		return killedStatusString
    78  	default:
    79  		return ""
    80  	}
    81  }
    82  
    83  // ComplianceFlags represents constraints that the code running must comply
    84  // with.
    85  type ComplianceFlags uint16
    86  
    87  const (
    88  	// Only execute code checks memory availability before allocating memory
    89  	ComplyMemSafe ComplianceFlags = 1 << iota
    90  
    91  	// Only execute code that checks cpu availability before executing a
    92  	// computation.
    93  	ComplyCpuSafe
    94  
    95  	// Only execute code that complies with IO restrictions (currently only
    96  	// functions that do no IO comply with this)
    97  	ComplyIoSafe
    98  
    99  	// Only execute code that is time safe (i.e. it will not block on long
   100  	// running ops, typically IO)
   101  	ComplyTimeSafe
   102  
   103  	complyflagsLimit
   104  )
   105  
   106  const (
   107  	memSafeString  = "memsafe"
   108  	cpuSafeString  = "cpusafe"
   109  	timeSafeString = "timesafe"
   110  	ioSafeString   = "iosafe"
   111  )
   112  
   113  var complianceFlagNames = map[ComplianceFlags]string{
   114  	ComplyMemSafe:  memSafeString,
   115  	ComplyCpuSafe:  cpuSafeString,
   116  	ComplyTimeSafe: timeSafeString,
   117  	ComplyIoSafe:   ioSafeString,
   118  }
   119  
   120  var complianceFlagsByName = map[string]ComplianceFlags{
   121  	memSafeString:  ComplyMemSafe,
   122  	cpuSafeString:  ComplyCpuSafe,
   123  	timeSafeString: ComplyTimeSafe,
   124  	ioSafeString:   ComplyIoSafe,
   125  }
   126  
   127  func (f ComplianceFlags) AddFlagWithName(name string) (ComplianceFlags, bool) {
   128  	fn, ok := complianceFlagsByName[name]
   129  	return fn | f, ok
   130  }
   131  
   132  func (f ComplianceFlags) Names() (names []string) {
   133  	var i ComplianceFlags
   134  	for i = 1; i < complyflagsLimit; i <<= 1 {
   135  		if i&f != 0 {
   136  			names = append(names, complianceFlagNames[i])
   137  		}
   138  	}
   139  	return names
   140  }
   141  
   142  // RuntimeResources describe amount of resources that code can consume.
   143  // Depending on the context, it could be available resources or consumed
   144  // resources.  For available resources, 0 means unlimited.
   145  type RuntimeResources struct {
   146  	Cpu    uint64
   147  	Memory uint64
   148  	Millis uint64
   149  }
   150  
   151  // Remove lowers the resources accounted for in the receiver by the resources
   152  // accounted for in the argument.
   153  func (r RuntimeResources) Remove(v RuntimeResources) RuntimeResources {
   154  	if r.Cpu >= v.Cpu {
   155  		r.Cpu -= v.Cpu
   156  	} else {
   157  		r.Cpu = 0
   158  	}
   159  	if r.Memory >= v.Memory {
   160  		r.Memory -= v.Memory
   161  	} else {
   162  		r.Memory = 0
   163  	}
   164  	if r.Millis >= v.Millis {
   165  		r.Millis -= v.Millis
   166  	} else {
   167  		r.Millis = 0
   168  	}
   169  	return r
   170  }
   171  
   172  // Merge treats the receiver and argument as describing resource limits and
   173  // returns the resources describing the intersection of those limits.
   174  func (r RuntimeResources) Merge(r1 RuntimeResources) RuntimeResources {
   175  	if smallerLimit(r1.Cpu, r.Cpu) {
   176  		r.Cpu = r1.Cpu
   177  	}
   178  	if smallerLimit(r1.Memory, r.Memory) {
   179  		r.Memory = r1.Memory
   180  	}
   181  	if smallerLimit(r1.Millis, r.Millis) {
   182  		r.Millis = r1.Millis
   183  	}
   184  	return r
   185  }
   186  
   187  // Dominates returns true if the resource count v doesn't reach the resource
   188  // limit r.
   189  func (r RuntimeResources) Dominates(v RuntimeResources) bool {
   190  	return !atLimit(v.Cpu, r.Cpu) && !atLimit(v.Memory, r.Memory) && !atLimit(v.Millis, r.Millis)
   191  }
   192  
   193  // n < m, but with 0 meaning +infinity for both n and m
   194  func smallerLimit(n, m uint64) bool {
   195  	return n > 0 && (m == 0 || n < m)
   196  }
   197  
   198  // l <= v, but with 0 meaning +infinity for l
   199  func atLimit(v, l uint64) bool {
   200  	return l > 0 && v >= l
   201  }
   202  
   203  type GCPolicy int16
   204  
   205  const (
   206  	DefaultGCPolicy GCPolicy = iota
   207  	ShareGCPolicy
   208  	IsolateGCPolicy
   209  	UnknownGCPolicy
   210  )