mirror of
https://github.com/superseriousbusiness/gotosocial.git
synced 2024-11-27 10:43:32 +01:00
acc333c40b
When GTS is running in a container runtime which has configured CPU or memory limits or under an init system that uses cgroups to impose CPU and memory limits the values the Go runtime sees for GOMAXPROCS and GOMEMLIMIT are still based on the host resources, not the cgroup. At least for the throttling middlewares which use GOMAXPROCS to configure their queue size, this can result in GTS running with values too big compared to the resources that will actuall be available to it. This introduces 2 dependencies which can pick up resource contraints from the current cgroup and tune the Go runtime accordingly. This should result in the different queues being appropriately sized and in general more predictable performance. These dependencies are a no-op on non-Linux systems or if running in a cgroup that doesn't set a limit on CPU or memory. The automatic tuning of GOMEMLIMIT can be disabled by either explicitly setting GOMEMLIMIT yourself or by setting AUTOMEMLIMIT=off. The automatic tuning of GOMAXPROCS can similarly be counteracted by setting GOMAXPROCS yourself.
260 lines
5.8 KiB
Go
260 lines
5.8 KiB
Go
package dbus
|
|
|
|
import (
|
|
"fmt"
|
|
"reflect"
|
|
"strings"
|
|
)
|
|
|
|
var sigToType = map[byte]reflect.Type{
|
|
'y': byteType,
|
|
'b': boolType,
|
|
'n': int16Type,
|
|
'q': uint16Type,
|
|
'i': int32Type,
|
|
'u': uint32Type,
|
|
'x': int64Type,
|
|
't': uint64Type,
|
|
'd': float64Type,
|
|
's': stringType,
|
|
'g': signatureType,
|
|
'o': objectPathType,
|
|
'v': variantType,
|
|
'h': unixFDIndexType,
|
|
}
|
|
|
|
// Signature represents a correct type signature as specified by the D-Bus
|
|
// specification. The zero value represents the empty signature, "".
|
|
type Signature struct {
|
|
str string
|
|
}
|
|
|
|
// SignatureOf returns the concatenation of all the signatures of the given
|
|
// values. It panics if one of them is not representable in D-Bus.
|
|
func SignatureOf(vs ...interface{}) Signature {
|
|
var s string
|
|
for _, v := range vs {
|
|
s += getSignature(reflect.TypeOf(v))
|
|
}
|
|
return Signature{s}
|
|
}
|
|
|
|
// SignatureOfType returns the signature of the given type. It panics if the
|
|
// type is not representable in D-Bus.
|
|
func SignatureOfType(t reflect.Type) Signature {
|
|
return Signature{getSignature(t)}
|
|
}
|
|
|
|
// getSignature returns the signature of the given type and panics on unknown types.
|
|
func getSignature(t reflect.Type) string {
|
|
// handle simple types first
|
|
switch t.Kind() {
|
|
case reflect.Uint8:
|
|
return "y"
|
|
case reflect.Bool:
|
|
return "b"
|
|
case reflect.Int16:
|
|
return "n"
|
|
case reflect.Uint16:
|
|
return "q"
|
|
case reflect.Int, reflect.Int32:
|
|
if t == unixFDType {
|
|
return "h"
|
|
}
|
|
return "i"
|
|
case reflect.Uint, reflect.Uint32:
|
|
if t == unixFDIndexType {
|
|
return "h"
|
|
}
|
|
return "u"
|
|
case reflect.Int64:
|
|
return "x"
|
|
case reflect.Uint64:
|
|
return "t"
|
|
case reflect.Float64:
|
|
return "d"
|
|
case reflect.Ptr:
|
|
return getSignature(t.Elem())
|
|
case reflect.String:
|
|
if t == objectPathType {
|
|
return "o"
|
|
}
|
|
return "s"
|
|
case reflect.Struct:
|
|
if t == variantType {
|
|
return "v"
|
|
} else if t == signatureType {
|
|
return "g"
|
|
}
|
|
var s string
|
|
for i := 0; i < t.NumField(); i++ {
|
|
field := t.Field(i)
|
|
if field.PkgPath == "" && field.Tag.Get("dbus") != "-" {
|
|
s += getSignature(t.Field(i).Type)
|
|
}
|
|
}
|
|
return "(" + s + ")"
|
|
case reflect.Array, reflect.Slice:
|
|
return "a" + getSignature(t.Elem())
|
|
case reflect.Map:
|
|
if !isKeyType(t.Key()) {
|
|
panic(InvalidTypeError{t})
|
|
}
|
|
return "a{" + getSignature(t.Key()) + getSignature(t.Elem()) + "}"
|
|
case reflect.Interface:
|
|
return "v"
|
|
}
|
|
panic(InvalidTypeError{t})
|
|
}
|
|
|
|
// ParseSignature returns the signature represented by this string, or a
|
|
// SignatureError if the string is not a valid signature.
|
|
func ParseSignature(s string) (sig Signature, err error) {
|
|
if len(s) == 0 {
|
|
return
|
|
}
|
|
if len(s) > 255 {
|
|
return Signature{""}, SignatureError{s, "too long"}
|
|
}
|
|
sig.str = s
|
|
for err == nil && len(s) != 0 {
|
|
err, s = validSingle(s, 0)
|
|
}
|
|
if err != nil {
|
|
sig = Signature{""}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// ParseSignatureMust behaves like ParseSignature, except that it panics if s
|
|
// is not valid.
|
|
func ParseSignatureMust(s string) Signature {
|
|
sig, err := ParseSignature(s)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
return sig
|
|
}
|
|
|
|
// Empty returns whether the signature is the empty signature.
|
|
func (s Signature) Empty() bool {
|
|
return s.str == ""
|
|
}
|
|
|
|
// Single returns whether the signature represents a single, complete type.
|
|
func (s Signature) Single() bool {
|
|
err, r := validSingle(s.str, 0)
|
|
return err != nil && r == ""
|
|
}
|
|
|
|
// String returns the signature's string representation.
|
|
func (s Signature) String() string {
|
|
return s.str
|
|
}
|
|
|
|
// A SignatureError indicates that a signature passed to a function or received
|
|
// on a connection is not a valid signature.
|
|
type SignatureError struct {
|
|
Sig string
|
|
Reason string
|
|
}
|
|
|
|
func (e SignatureError) Error() string {
|
|
return fmt.Sprintf("dbus: invalid signature: %q (%s)", e.Sig, e.Reason)
|
|
}
|
|
|
|
// Try to read a single type from this string. If it was successful, err is nil
|
|
// and rem is the remaining unparsed part. Otherwise, err is a non-nil
|
|
// SignatureError and rem is "". depth is the current recursion depth which may
|
|
// not be greater than 64 and should be given as 0 on the first call.
|
|
func validSingle(s string, depth int) (err error, rem string) {
|
|
if s == "" {
|
|
return SignatureError{Sig: s, Reason: "empty signature"}, ""
|
|
}
|
|
if depth > 64 {
|
|
return SignatureError{Sig: s, Reason: "container nesting too deep"}, ""
|
|
}
|
|
switch s[0] {
|
|
case 'y', 'b', 'n', 'q', 'i', 'u', 'x', 't', 'd', 's', 'g', 'o', 'v', 'h':
|
|
return nil, s[1:]
|
|
case 'a':
|
|
if len(s) > 1 && s[1] == '{' {
|
|
i := findMatching(s[1:], '{', '}')
|
|
if i == -1 {
|
|
return SignatureError{Sig: s, Reason: "unmatched '{'"}, ""
|
|
}
|
|
i++
|
|
rem = s[i+1:]
|
|
s = s[2:i]
|
|
if err, _ = validSingle(s[:1], depth+1); err != nil {
|
|
return err, ""
|
|
}
|
|
err, nr := validSingle(s[1:], depth+1)
|
|
if err != nil {
|
|
return err, ""
|
|
}
|
|
if nr != "" {
|
|
return SignatureError{Sig: s, Reason: "too many types in dict"}, ""
|
|
}
|
|
return nil, rem
|
|
}
|
|
return validSingle(s[1:], depth+1)
|
|
case '(':
|
|
i := findMatching(s, '(', ')')
|
|
if i == -1 {
|
|
return SignatureError{Sig: s, Reason: "unmatched ')'"}, ""
|
|
}
|
|
rem = s[i+1:]
|
|
s = s[1:i]
|
|
for err == nil && s != "" {
|
|
err, s = validSingle(s, depth+1)
|
|
}
|
|
if err != nil {
|
|
rem = ""
|
|
}
|
|
return
|
|
}
|
|
return SignatureError{Sig: s, Reason: "invalid type character"}, ""
|
|
}
|
|
|
|
func findMatching(s string, left, right rune) int {
|
|
n := 0
|
|
for i, v := range s {
|
|
if v == left {
|
|
n++
|
|
} else if v == right {
|
|
n--
|
|
}
|
|
if n == 0 {
|
|
return i
|
|
}
|
|
}
|
|
return -1
|
|
}
|
|
|
|
// typeFor returns the type of the given signature. It ignores any left over
|
|
// characters and panics if s doesn't start with a valid type signature.
|
|
func typeFor(s string) (t reflect.Type) {
|
|
err, _ := validSingle(s, 0)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
|
|
if t, ok := sigToType[s[0]]; ok {
|
|
return t
|
|
}
|
|
switch s[0] {
|
|
case 'a':
|
|
if s[1] == '{' {
|
|
i := strings.LastIndex(s, "}")
|
|
t = reflect.MapOf(sigToType[s[2]], typeFor(s[3:i]))
|
|
} else {
|
|
t = reflect.SliceOf(typeFor(s[1:]))
|
|
}
|
|
case '(':
|
|
t = interfacesType
|
|
}
|
|
return
|
|
}
|