diff options
| -rw-r--r-- | prog/decl_test.go | 35 | ||||
| -rw-r--r-- | prog/resources.go | 128 |
2 files changed, 102 insertions, 61 deletions
diff --git a/prog/decl_test.go b/prog/decl_test.go index 0f727aa7f..ac353e66a 100644 --- a/prog/decl_test.go +++ b/prog/decl_test.go @@ -14,11 +14,11 @@ func TestResourceCtors(t *testing.T) { } testEachTarget(t, func(t *testing.T, target *Target) { for _, c := range target.Syscalls { - for _, res := range c.inputResources() { - if len(target.calcResourceCtors(res.Desc.Kind, true)) == 0 { + for _, res := range target.inputResources(c) { + if len(target.calcResourceCtors(res.Kind, true)) == 0 { t.Errorf("call %v requires input resource %v,"+ " but there are no calls that can create this resource", - c.Name, res.Desc.Name) + c.Name, res.Name) } } } @@ -31,18 +31,29 @@ func TestTransitivelyEnabledCalls(t *testing.T) { for _, c := range target.Syscalls { calls[c] = true } - if trans, disabled := target.TransitivelyEnabledCalls(calls); len(disabled) != 0 { + enabled, disabled := target.TransitivelyEnabledCalls(calls) + for c, ok := range enabled { + if !ok { + t.Fatalf("syscalls %v is false in enabled map", c.Name) + } + } + if target.OS == "test" { + for c := range enabled { + if c.CallName == "unsupported" { + t.Errorf("call %v is not disabled", c.Name) + } + } for c, reason := range disabled { - t.Logf("disabled %v: %v", c.Name, reason) + if c.CallName != "unsupported" { + t.Errorf("call %v is disabled: %v", c.Name, reason) + } } - t.Fatalf("can't create some resource") - } else if len(trans) != len(calls) { - t.Fatalf("transitive syscalls are not full") } else { - for c, ok := range trans { - if !ok { - t.Fatalf("syscalls %v is false in transitive map", c.Name) - } + if len(enabled) != len(target.Syscalls) { + t.Errorf("some calls are disabled: %v/%v", len(enabled), len(target.Syscalls)) + } + for c, reason := range disabled { + t.Errorf("disabled %v: %v", c.Name, reason) } } }) diff --git a/prog/resources.go b/prog/resources.go index 68fbe1599..bddb158d9 100644 --- a/prog/resources.go +++ b/prog/resources.go @@ -7,6 +7,13 @@ import ( "fmt" ) +// We need to support structs as resources, +// but for now we just special-case timespec/timeval. +var timespecRes = &ResourceDesc{ + Name: "timespec", + Kind: []string{"timespec"}, +} + func (target *Target) calcResourceCtors(kind []string, precise bool) []*Syscall { // Find calls that produce the necessary resources. var metas []*Syscall @@ -28,6 +35,11 @@ func (target *Target) calcResourceCtors(kind []string, precise bool) []*Syscall metas = append(metas, meta) } } + if kind[0] == timespecRes.Name { + if c := target.SyscallMap["clock_gettime"]; c != nil { + metas = append(metas, c) + } + } return metas } @@ -72,82 +84,100 @@ func isCompatibleResourceImpl(dst, src []string, precise bool) bool { return true } -func (c *Syscall) inputResources() []*ResourceType { - var resources []*ResourceType +func (target *Target) inputResources(c *Syscall) []*ResourceDesc { + var resources []*ResourceDesc + ForeachType(c, func(typ Type) { + if typ.Dir() == DirOut { + return + } + switch typ1 := typ.(type) { + case *ResourceType: + if !typ1.IsOptional { + resources = append(resources, typ1.Desc) + } + case *StructType: + if target.OS == "linux" && (typ1.Name() == "timespec" || typ1.Name() == "timeval") { + resources = append(resources, timespecRes) + } + } + }) + return resources +} + +func (target *Target) outputResources(c *Syscall) []*ResourceDesc { + var resources []*ResourceDesc ForeachType(c, func(typ Type) { switch typ1 := typ.(type) { case *ResourceType: - if typ1.Dir() != DirOut && !typ1.IsOptional { - resources = append(resources, typ1) + if typ1.Dir() != DirIn { + resources = append(resources, typ1.Desc) } } }) + if c.CallName == "clock_gettime" { + resources = append(resources, timespecRes) + } return resources } func (target *Target) TransitivelyEnabledCalls(enabled map[*Syscall]bool) (map[*Syscall]bool, map[*Syscall]string) { supported := make(map[*Syscall]bool) disabled := make(map[*Syscall]string) + canCreate := make(map[string]bool) + inputResources := make(map[*Syscall][]*ResourceDesc) for c := range enabled { - supported[c] = true - } - inputResources := make(map[*Syscall][]*ResourceType) - ctors := make(map[string][]*Syscall) - for c := range supported { - inputs := c.inputResources() - inputResources[c] = inputs - for _, res := range inputs { - if _, ok := ctors[res.Desc.Name]; ok { - continue - } - ctors[res.Desc.Name] = target.calcResourceCtors(res.Desc.Kind, true) - } + inputResources[c] = target.inputResources(c) } for { n := len(supported) - haveGettime := supported[target.SyscallMap["clock_gettime"]] - for c := range supported { - cantCreate := "" - var resourceCtors []*Syscall + for c := range enabled { + if supported[c] { + continue + } + ready := true for _, res := range inputResources[c] { - noctors := true - for _, ctor := range ctors[res.Desc.Name] { - if supported[ctor] { - noctors = false - break - } - } - if noctors { - cantCreate = res.Desc.Name - resourceCtors = ctors[res.Desc.Name] + if !canCreate[res.Name] { + ready = false break } } - // We need to support structs as resources, - // but for now we just special-case timespec/timeval. - if cantCreate == "" && !haveGettime && target.SyscallMap["clock_gettime"] != nil { - ForeachType(c, func(typ Type) { - if a, ok := typ.(*StructType); ok && a.Dir() != DirOut && - (a.Name() == "timespec" || a.Name() == "timeval") { - cantCreate = a.Name() - resourceCtors = []*Syscall{target.SyscallMap["clock_gettime"]} + if ready { + supported[c] = true + for _, res := range target.outputResources(c) { + for _, kind := range res.Kind { + canCreate[kind] = true } - }) - } - if cantCreate != "" { - delete(supported, c) - var ctorNames []string - for _, ctor := range resourceCtors { - ctorNames = append(ctorNames, ctor.Name) } - disabled[c] = fmt.Sprintf("no syscalls can create resource %v,"+ - " enable some syscalls that can create it %v", - cantCreate, ctorNames) } } if n == len(supported) { break } } + ctors := make(map[string][]string) + for c := range enabled { + if supported[c] { + continue + } + for _, res := range inputResources[c] { + if canCreate[res.Name] { + continue + } + if ctors[res.Name] == nil { + var names []string + for _, call := range target.calcResourceCtors(res.Kind, true) { + names = append(names, call.Name) + } + ctors[res.Name] = names + } + disabled[c] = fmt.Sprintf("no syscalls can create resource %v,"+ + " enable some syscalls that can create it %v", + res.Name, ctors[res.Name]) + break + } + } + if len(enabled) != len(supported)+len(disabled) { + panic("lost syscalls") + } return supported, disabled } |
