You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@mynewt.apache.org by cc...@apache.org on 2018/10/23 17:47:57 UTC

[mynewt-newt] branch master updated (2f12a97 -> 6cde323)

This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a change to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-newt.git.


    from 2f12a97  Merge pull request #222 from michal-narajowski/travis
     new 484bbb4  Genericize sysinit functionality
     new 6cde323  sysdown: generate package shutdown function

The 2 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.


Summary of changes:
 newt/builder/targetbuild.go |  23 +++++
 newt/pkg/localpackage.go    |  23 ++++-
 newt/stage/stage.go         | 204 ++++++++++++++++++++++++++++++++++++++++++++
 newt/sysdown/sysdown.go     |  97 +++++++++++++++++++++
 newt/sysinit/sysinit.go     | 163 +++++------------------------------
 util/util.go                |  17 ++++
 6 files changed, 382 insertions(+), 145 deletions(-)
 create mode 100644 newt/stage/stage.go
 create mode 100644 newt/sysdown/sysdown.go


[mynewt-newt] 02/02: sysdown: generate package shutdown function

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-newt.git

commit 6cde3237a522448062936a6815219cf43f82873e
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Thu Oct 4 18:53:19 2018 -0700

    sysdown: generate package shutdown function
    
    Allow packages to specify a function to call when the system shuts down.
    The syntax is:
    
        pkg.down:
            <C-function-name>: <stage-number>
    
    e.g.,
    
        pkg.down:
            ble_hs_shutdown: 200
    
    Lower stages execute before greater stages.  If two or more callbacks
    have the same stage, they are sorted alphabetically by C function name.
---
 newt/builder/targetbuild.go | 23 +++++++++++
 newt/pkg/localpackage.go    | 23 ++++++++++-
 newt/sysdown/sysdown.go     | 97 +++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 142 insertions(+), 1 deletion(-)

diff --git a/newt/builder/targetbuild.go b/newt/builder/targetbuild.go
index 1c2f8ba..e4ccc21 100644
--- a/newt/builder/targetbuild.go
+++ b/newt/builder/targetbuild.go
@@ -45,6 +45,7 @@ import (
 	"mynewt.apache.org/newt/newt/resolve"
 	"mynewt.apache.org/newt/newt/symbol"
 	"mynewt.apache.org/newt/newt/syscfg"
+	"mynewt.apache.org/newt/newt/sysdown"
 	"mynewt.apache.org/newt/newt/sysinit"
 	"mynewt.apache.org/newt/newt/target"
 	"mynewt.apache.org/newt/newt/toolchain"
@@ -172,6 +173,10 @@ func (t *TargetBuilder) ensureResolved() error {
 		appSeeds = append(appSeeds, t.testPkg)
 	}
 
+	// Indicate to the apache-mynewt-core code that this version of newt
+	// supports the sysdown mechanism (generated package shutdown functions).
+	t.injectedSettings["NEWT_FEATURE_SYSDOWN"] = "1"
+
 	var err error
 	t.res, err = resolve.ResolveFull(
 		loaderSeeds, appSeeds, t.injectedSettings, t.bspPkg.FlashMap)
@@ -237,6 +242,20 @@ func (t *TargetBuilder) generateSysinit() error {
 	return nil
 }
 
+func (t *TargetBuilder) generateSysdown() error {
+	if err := t.ensureResolved(); err != nil {
+		return err
+	}
+
+	srcDir := GeneratedSrcDir(t.target.Name())
+
+	lpkgs := resolve.RpkgSliceToLpkgSlice(t.res.AppSet.Rpkgs)
+	sysdown.EnsureWritten(lpkgs, t.res.Cfg, srcDir,
+		pkg.ShortName(t.target.Package()))
+
+	return nil
+}
+
 func (t *TargetBuilder) generateFlashMap() error {
 	return t.bspPkg.FlashMap.EnsureWritten(
 		GeneratedSrcDir(t.target.Name()),
@@ -249,6 +268,10 @@ func (t *TargetBuilder) generateCode() error {
 		return err
 	}
 
+	if err := t.generateSysdown(); err != nil {
+		return err
+	}
+
 	if err := t.generateFlashMap(); err != nil {
 		return err
 	}
diff --git a/newt/pkg/localpackage.go b/newt/pkg/localpackage.go
index 6927b38..d5cc9a8 100644
--- a/newt/pkg/localpackage.go
+++ b/newt/pkg/localpackage.go
@@ -361,9 +361,10 @@ func (pkg *LocalPackage) Load() error {
 		}
 		pkg.init[name] = int(stage)
 	}
+
+	// Backwards compatibility: allow old sysinit notation.
 	initFnName := pkg.PkgY.GetValString("pkg.init_function", nil)
 	initStage := pkg.PkgY.GetValInt("pkg.init_stage", nil)
-
 	if initFnName != "" {
 		pkg.init[initFnName] = initStage
 	}
@@ -391,6 +392,26 @@ func (pkg *LocalPackage) Init() map[string]int {
 	return pkg.init
 }
 
+// DownFuncs retrieves the package's shutdown functions.  The returned map has:
+// key=C-function-name, value=numeric-stage.
+func (pkg *LocalPackage) DownFuncs(
+	settings map[string]string) (map[string]int, error) {
+
+	downFuncs := map[string]int{}
+
+	down := pkg.PkgY.GetValStringMapString("pkg.down", settings)
+	for name, stageStr := range down {
+		stage, err := strconv.ParseInt(stageStr, 10, 64)
+		if err != nil {
+			return nil, util.FmtNewtError("Parsing pkg %s config: %s",
+				pkg.FullName(), err.Error())
+		}
+		downFuncs[name] = int(stage)
+	}
+
+	return downFuncs, nil
+}
+
 func (pkg *LocalPackage) InjectedSettings() map[string]string {
 	return pkg.injectedSettings
 }
diff --git a/newt/sysdown/sysdown.go b/newt/sysdown/sysdown.go
new file mode 100644
index 0000000..060130e
--- /dev/null
+++ b/newt/sysdown/sysdown.go
@@ -0,0 +1,97 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package sysdown
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+
+	"mynewt.apache.org/newt/newt/newtutil"
+	"mynewt.apache.org/newt/newt/pkg"
+	"mynewt.apache.org/newt/newt/stage"
+	"mynewt.apache.org/newt/newt/syscfg"
+)
+
+// downFuncs collects the sysdown functions corresponding to the provided
+// packages.
+func downFuncs(pkgs []*pkg.LocalPackage,
+	cfg syscfg.Cfg) ([]stage.StageFunc, error) {
+
+	fns := make([]stage.StageFunc, 0, len(pkgs))
+	for _, p := range pkgs {
+		downMap, err := p.DownFuncs(cfg.AllSettingsForLpkg(p))
+		if err != nil {
+			return nil, err
+		}
+
+		for name, stageNum := range downMap {
+			fn := stage.StageFunc{
+				Name:       name,
+				Stage:      stageNum,
+				ReturnType: "int",
+				ArgList:    "int reason",
+				Pkg:        p,
+			}
+			fns = append(fns, fn)
+		}
+	}
+
+	return fns, nil
+}
+
+func sortedDownFuncs(pkgs []*pkg.LocalPackage,
+	cfg syscfg.Cfg) ([]stage.StageFunc, error) {
+
+	fns, err := downFuncs(pkgs, cfg)
+	if err != nil {
+		return nil, err
+	}
+
+	stage.SortStageFuncs(fns, "sysdown")
+	return fns, nil
+}
+
+func write(pkgs []*pkg.LocalPackage, cfg syscfg.Cfg, w io.Writer) error {
+	fmt.Fprintf(w, newtutil.GeneratedPreamble())
+
+	fns, err := sortedDownFuncs(pkgs, cfg)
+	if err != nil {
+		return err
+	}
+
+	stage.WritePrototypes(fns, w)
+
+	fmt.Fprintf(w, "\nint (* const sysdown_cbs[])(int reason) = {\n")
+	stage.WriteArr(fns, w)
+	fmt.Fprintf(w, "};\n")
+
+	return nil
+}
+
+func EnsureWritten(pkgs []*pkg.LocalPackage, cfg syscfg.Cfg, srcDir string,
+	targetName string) error {
+
+	buf := bytes.Buffer{}
+	write(pkgs, cfg, &buf)
+
+	path := fmt.Sprintf("%s/%s-sysdown.c", srcDir, targetName)
+	return stage.EnsureWritten(path, buf.Bytes())
+}


[mynewt-newt] 01/02: Genericize sysinit functionality

Posted by cc...@apache.org.
This is an automated email from the ASF dual-hosted git repository.

ccollins pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/mynewt-newt.git

commit 484bbb4729ea39ff616f0758358d6fe833d7fb50
Author: Christopher Collins <cc...@apache.org>
AuthorDate: Thu Sep 27 15:18:51 2018 -0700

    Genericize sysinit functionality
    
    Create a `stage` package.  This package emits C code consisting of
    a sequence of function calls.
---
 newt/stage/stage.go     | 204 ++++++++++++++++++++++++++++++++++++++++++++++++
 newt/sysinit/sysinit.go | 163 +++++---------------------------------
 util/util.go            |  17 ++++
 3 files changed, 240 insertions(+), 144 deletions(-)

diff --git a/newt/stage/stage.go b/newt/stage/stage.go
new file mode 100644
index 0000000..ee2dead
--- /dev/null
+++ b/newt/stage/stage.go
@@ -0,0 +1,204 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License.  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied.  See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+// stage - utility for generating C code consisting of a sequence of function
+// calls ordered by stage number.
+//
+// This package is used by sysinit and sysdown.
+
+package stage
+
+import (
+	"fmt"
+	"io"
+	"io/ioutil"
+	"os"
+	"path/filepath"
+	"sort"
+	"strings"
+
+	log "github.com/Sirupsen/logrus"
+
+	"mynewt.apache.org/newt/newt/pkg"
+	"mynewt.apache.org/newt/util"
+)
+
+type StageFunc struct {
+	Stage      int
+	Name       string
+	ReturnType string
+	ArgList    string
+	Pkg        *pkg.LocalPackage
+}
+
+type stageFuncSorter struct {
+	// Used in logging; either "sysinit" or "sysdown".
+	funcType string
+	// Array of functions to be sorted.
+	fns []StageFunc
+}
+
+func (s stageFuncSorter) Len() int {
+	return len(s.fns)
+}
+
+func (s stageFuncSorter) Swap(i, j int) {
+	s.fns[i], s.fns[j] = s.fns[j], s.fns[i]
+}
+
+func (s stageFuncSorter) Less(i, j int) bool {
+	a := s.fns[i]
+	b := s.fns[j]
+
+	// 1: Sort by stage number.
+	if a.Stage < b.Stage {
+		return true
+	} else if b.Stage < a.Stage {
+		return false
+	}
+
+	// 2: Sort by function name.
+	switch strings.Compare(a.Name, b.Name) {
+	case -1:
+		return true
+	case 1:
+		return false
+	}
+
+	// Same stage and function name?
+	log.Warnf("Warning: Identical %s functions detected: %s",
+		s.funcType, a.Name)
+
+	return true
+}
+
+// SortStageFuncs performs an in-place sort of the provided StageFunc slice.
+func SortStageFuncs(unsorted []StageFunc, funcType string) {
+	s := stageFuncSorter{
+		funcType: funcType,
+		fns:      unsorted,
+	}
+
+	sort.Sort(s)
+}
+
+func (f *StageFunc) ReturnTypeString() string {
+	if f.ReturnType == "" {
+		return "void"
+	} else {
+		return f.ReturnType
+	}
+}
+
+func (f *StageFunc) ArgListString() string {
+	if f.ArgList == "" {
+		return "void"
+	} else {
+		return f.ArgList
+	}
+}
+
+// WriteCalls emits C code: a list of function prototypes corresponding to the
+// provided slice of stage functions.
+func WritePrototypes(sortedFns []StageFunc, w io.Writer) {
+	for _, f := range sortedFns {
+		fmt.Fprintf(w, "%s %s(%s);\n",
+			f.ReturnTypeString(), f.Name, f.ArgListString())
+	}
+}
+
+// WriteCalls emits C code: a sequence of function calls corresponding to the
+// provided slice of stage functions.
+func WriteCalls(sortedFuncs []StageFunc, argList string, w io.Writer) {
+	prevStage := -1
+	dupCount := 0
+
+	for i, f := range sortedFuncs {
+		if f.Stage != prevStage {
+			prevStage = f.Stage
+			dupCount = 0
+
+			if i != 0 {
+				fmt.Fprintf(w, "\n")
+			}
+			fmt.Fprintf(w, "    /*** Stage %d */\n", f.Stage)
+		} else {
+			dupCount += 1
+		}
+
+		fmt.Fprintf(w, "    /* %d.%d: %s (%s) */\n",
+			f.Stage, dupCount, f.Name, f.Pkg.Name())
+		fmt.Fprintf(w, "    %s(%s);\n", f.Name, argList)
+	}
+}
+
+// WriteArr emits C code: an array body of function pointers represented by the
+// supplied slice.  The caller must 1) write the array declaration before
+// calling this function, and 2) write "};" afterwards.
+func WriteArr(sortedFuncs []StageFunc, w io.Writer) {
+	prevStage := -1
+	dupCount := 0
+
+	for i, f := range sortedFuncs {
+		if f.Stage != prevStage {
+			prevStage = f.Stage
+			dupCount = 0
+
+			if i != 0 {
+				fmt.Fprintf(w, "\n")
+			}
+			fmt.Fprintf(w, "    /*** Stage %d */\n", f.Stage)
+		} else {
+			dupCount += 1
+		}
+
+		fmt.Fprintf(w, "    /* %d.%d: %s (%s) */\n",
+			f.Stage, dupCount, f.Name, f.Pkg.Name())
+		fmt.Fprintf(w, "    %s,\n", f.Name)
+	}
+	fmt.Fprintf(w, "\n")
+	fmt.Fprintf(w, "    /*** Array terminator. */\n")
+	fmt.Fprintf(w, "    0\n")
+}
+
+// EnsureWritten writes the specified file if its contents differ from those of
+// the supplied byte slice.
+func EnsureWritten(path string, contents []byte) error {
+	unchanged, err := util.FileContains(contents, path)
+	if err != nil {
+		return err
+	}
+
+	if unchanged {
+		log.Debugf("file unchanged; not writing src file (%s).", path)
+		return nil
+	}
+
+	log.Debugf("file changed; writing src file (%s).", path)
+
+	if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
+		return util.NewNewtError(err.Error())
+	}
+
+	if err := ioutil.WriteFile(path, contents, 0644); err != nil {
+		return util.NewNewtError(err.Error())
+	}
+
+	return nil
+}
diff --git a/newt/sysinit/sysinit.go b/newt/sysinit/sysinit.go
index 4071a09..98e7fc6 100644
--- a/newt/sysinit/sysinit.go
+++ b/newt/sysinit/sysinit.go
@@ -23,125 +23,33 @@ import (
 	"bytes"
 	"fmt"
 	"io"
-	"io/ioutil"
-	"os"
-	"path/filepath"
-	"sort"
-	"strings"
-
-	log "github.com/Sirupsen/logrus"
 
 	"mynewt.apache.org/newt/newt/newtutil"
 	"mynewt.apache.org/newt/newt/pkg"
-	"mynewt.apache.org/newt/util"
+	"mynewt.apache.org/newt/newt/stage"
 )
 
-type initFunc struct {
-	stage int
-	name  string
-	pkg   *pkg.LocalPackage
-}
-
-func buildStageMap(pkgs []*pkg.LocalPackage) map[int][]*initFunc {
-	sm := map[int][]*initFunc{}
-
-	for _, p := range pkgs {
-		for name, stage := range p.Init() {
-			initFunc := &initFunc{
-				stage: stage,
-				name:  name,
-				pkg:   p,
-			}
-			sm[stage] = append(sm[stage], initFunc)
-		}
-	}
-
-	return sm
-}
-
-type initFuncSorter struct {
-	fns []*initFunc
-}
-
-func (s initFuncSorter) Len() int {
-	return len(s.fns)
-}
-func (s initFuncSorter) Swap(i, j int) {
-	s.fns[i], s.fns[j] = s.fns[j], s.fns[i]
-}
-func (s initFuncSorter) Less(i, j int) bool {
-	a := s.fns[i]
-	b := s.fns[j]
-
-	// 1: Sort by stage number.
-	if a.stage < b.stage {
-		return true
-	} else if b.stage < a.stage {
-		return false
-	}
-
-	// 2: Sort by function name.
-	switch strings.Compare(a.name, b.name) {
-	case -1:
-		return true
-	case 1:
-		return false
-	}
-
-	// Same stage and function name?
-	log.Warnf("Warning: Identical sysinit functions detected: %s", a.name)
-	return true
-}
-
-func sortedInitFuncs(pkgs []*pkg.LocalPackage) []*initFunc {
-	sorter := initFuncSorter{
-		fns: make([]*initFunc, 0, len(pkgs)),
-	}
-
+func initFuncs(pkgs []*pkg.LocalPackage) []stage.StageFunc {
+	fns := make([]stage.StageFunc, 0, len(pkgs))
 	for _, p := range pkgs {
 		initMap := p.Init()
-		for name, stage := range initMap {
-			fn := &initFunc{
-				name:  name,
-				stage: stage,
-				pkg:   p,
+		for name, stageNum := range initMap {
+			fn := stage.StageFunc{
+				Name:  name,
+				Stage: stageNum,
+				Pkg:   p,
 			}
-			sorter.fns = append(sorter.fns, fn)
+			fns = append(fns, fn)
 		}
 	}
 
-	sort.Sort(sorter)
-	return sorter.fns
-}
-
-func writePrototypes(pkgs []*pkg.LocalPackage, w io.Writer) {
-	sortedFns := sortedInitFuncs(pkgs)
-	for _, f := range sortedFns {
-		fmt.Fprintf(w, "void %s(void);\n", f.name)
-	}
+	return fns
 }
 
-func writeCalls(sortedInitFuncs []*initFunc, w io.Writer) {
-	prevStage := -1
-	dupCount := 0
-
-	for i, f := range sortedInitFuncs {
-		if f.stage != prevStage {
-			prevStage = f.stage
-			dupCount = 0
-
-			if i != 0 {
-				fmt.Fprintf(w, "\n")
-			}
-			fmt.Fprintf(w, "    /*** Stage %d */\n", f.stage)
-		} else {
-			dupCount += 1
-		}
-
-		fmt.Fprintf(w, "    /* %d.%d: %s (%s) */\n",
-			f.stage, dupCount, f.name, f.pkg.Name())
-		fmt.Fprintf(w, "    %s();\n", f.name)
-	}
+func sortedInitFuncs(pkgs []*pkg.LocalPackage) []stage.StageFunc {
+	fns := initFuncs(pkgs)
+	stage.SortStageFuncs(fns, "sysinit")
+	return fns
 }
 
 func write(pkgs []*pkg.LocalPackage, isLoader bool,
@@ -155,7 +63,9 @@ func write(pkgs []*pkg.LocalPackage, isLoader bool,
 		fmt.Fprintf(w, "#if !SPLIT_LOADER\n\n")
 	}
 
-	writePrototypes(pkgs, w)
+	fns := sortedInitFuncs(pkgs)
+
+	stage.WritePrototypes(fns, w)
 
 	var fnName string
 	if isLoader {
@@ -167,27 +77,12 @@ func write(pkgs []*pkg.LocalPackage, isLoader bool,
 	fmt.Fprintf(w, "\n")
 	fmt.Fprintf(w, "void\n%s(void)\n{\n", fnName)
 
-	writeCalls(sortedInitFuncs(pkgs), w)
+	stage.WriteCalls(fns, "", w)
 
 	fmt.Fprintf(w, "}\n\n")
 	fmt.Fprintf(w, "#endif\n")
 }
 
-func writeRequired(contents []byte, path string) (bool, error) {
-	oldSrc, err := ioutil.ReadFile(path)
-	if err != nil {
-		if os.IsNotExist(err) {
-			// File doesn't exist; write required.
-			return true, nil
-		}
-
-		return true, util.NewNewtError(err.Error())
-	}
-
-	rc := bytes.Compare(oldSrc, contents)
-	return rc != 0, nil
-}
-
 func EnsureWritten(pkgs []*pkg.LocalPackage, srcDir string, targetName string,
 	isLoader bool) error {
 
@@ -201,25 +96,5 @@ func EnsureWritten(pkgs []*pkg.LocalPackage, srcDir string, targetName string,
 		path = fmt.Sprintf("%s/%s-sysinit-app.c", srcDir, targetName)
 	}
 
-	writeReqd, err := writeRequired(buf.Bytes(), path)
-	if err != nil {
-		return err
-	}
-
-	if !writeReqd {
-		log.Debugf("sysinit unchanged; not writing src file (%s).", path)
-		return nil
-	}
-
-	log.Debugf("sysinit changed; writing src file (%s).", path)
-
-	if err := os.MkdirAll(filepath.Dir(path), 0755); err != nil {
-		return util.NewNewtError(err.Error())
-	}
-
-	if err := ioutil.WriteFile(path, buf.Bytes(), 0644); err != nil {
-		return util.NewNewtError(err.Error())
-	}
-
-	return nil
+	return stage.EnsureWritten(path, buf.Bytes())
 }
diff --git a/util/util.go b/util/util.go
index e848642..d3abfc3 100644
--- a/util/util.go
+++ b/util/util.go
@@ -696,3 +696,20 @@ func StringMapStringToItfMapItf(
 
 	return imi
 }
+
+// FileContains indicates whether the specified file's contents are equal to
+// the provided byte slice.
+func FileContains(contents []byte, path string) (bool, error) {
+	oldSrc, err := ioutil.ReadFile(path)
+	if err != nil {
+		if os.IsNotExist(err) {
+			// File doesn't exist; contents aren't equal.
+			return false, nil
+		}
+
+		return false, NewNewtError(err.Error())
+	}
+
+	rc := bytes.Compare(oldSrc, contents)
+	return rc == 0, nil
+}