| @@ -907,6 +907,7 @@ golang.org/x/net v0.0.0-20200301022130-244492dfa37a/go.mod h1:z5CRVTTTmAJ677TzLL | |||
| golang.org/x/net v0.0.0-20200506145744-7e3656a0809f/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= | |||
| golang.org/x/net v0.0.0-20200513185701-a91f0712d120 h1:EZ3cVSzKOlJxAd8e8YAJ7no8nNypTxexh/YE/xW3ZEY= | |||
| golang.org/x/net v0.0.0-20200513185701-a91f0712d120/go.mod h1:qpuaurCH72eLCgpAm/N6yyVIVM9cpaDIP3A8BGJEC5A= | |||
| golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4 h1:4nGaVu0QrbjT/AK2PRLuQfQuh6DJve+pELhqTdAj3x0= | |||
| golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= | |||
| golang.org/x/oauth2 v0.0.0-20180620175406-ef147856a6dd/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | |||
| golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= | |||
| @@ -927,6 +928,7 @@ golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJ | |||
| golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
| golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a h1:WXEvlFVvvGxCJLG6REjsT03iWnKLEWinaScsxF2Vm2o= | |||
| golang.org/x/sync v0.0.0-20200317015054-43a5402ce75a/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
| golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= | |||
| golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= | |||
| golang.org/x/sys v0.0.0-20180824143301-4910a1d54f87/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
| golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= | |||
| @@ -971,6 +973,7 @@ golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |||
| golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= | |||
| golang.org/x/text v0.3.2 h1:tW2bmiBqwgJj/UpqtC8EpXEZVYOwU0yG4iWbprSVAcs= | |||
| golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= | |||
| golang.org/x/text v0.3.3 h1:cokOdA+Jmi5PJGXLlLllQSgYigAEfHXJAERHVMaCc2k= | |||
| golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= | |||
| golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | |||
| golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= | |||
| @@ -97,6 +97,7 @@ package module | |||
| import ( | |||
| "fmt" | |||
| "path" | |||
| "sort" | |||
| "strings" | |||
| "unicode" | |||
| @@ -223,14 +224,18 @@ func firstPathOK(r rune) bool { | |||
| 'a' <= r && r <= 'z' | |||
| } | |||
| // pathOK reports whether r can appear in an import path element. | |||
| // Paths can be ASCII letters, ASCII digits, and limited ASCII punctuation: + - . _ and ~. | |||
| // This matches what "go get" has historically recognized in import paths. | |||
| // modPathOK reports whether r can appear in a module path element. | |||
| // Paths can be ASCII letters, ASCII digits, and limited ASCII punctuation: - . _ and ~. | |||
| // | |||
| // This matches what "go get" has historically recognized in import paths, | |||
| // and avoids confusing sequences like '%20' or '+' that would change meaning | |||
| // if used in a URL. | |||
| // | |||
| // TODO(rsc): We would like to allow Unicode letters, but that requires additional | |||
| // care in the safe encoding (see "escaped paths" above). | |||
| func pathOK(r rune) bool { | |||
| func modPathOK(r rune) bool { | |||
| if r < utf8.RuneSelf { | |||
| return r == '+' || r == '-' || r == '.' || r == '_' || r == '~' || | |||
| return r == '-' || r == '.' || r == '_' || r == '~' || | |||
| '0' <= r && r <= '9' || | |||
| 'A' <= r && r <= 'Z' || | |||
| 'a' <= r && r <= 'z' | |||
| @@ -238,6 +243,17 @@ func pathOK(r rune) bool { | |||
| return false | |||
| } | |||
| // modPathOK reports whether r can appear in a package import path element. | |||
| // | |||
| // Import paths are intermediate between module paths and file paths: we allow | |||
| // disallow characters that would be confusing or ambiguous as arguments to | |||
| // 'go get' (such as '@' and ' ' ), but allow certain characters that are | |||
| // otherwise-unambiguous on the command line and historically used for some | |||
| // binary names (such as '++' as a suffix for compiler binaries and wrappers). | |||
| func importPathOK(r rune) bool { | |||
| return modPathOK(r) || r == '+' | |||
| } | |||
| // fileNameOK reports whether r can appear in a file name. | |||
| // For now we allow all Unicode letters but otherwise limit to pathOK plus a few more punctuation characters. | |||
| // If we expand the set of allowed characters here, we have to | |||
| @@ -269,7 +285,7 @@ func fileNameOK(r rune) bool { | |||
| // CheckPath checks that a module path is valid. | |||
| // A valid module path is a valid import path, as checked by CheckImportPath, | |||
| // with two additional constraints. | |||
| // with three additional constraints. | |||
| // First, the leading path element (up to the first slash, if any), | |||
| // by convention a domain name, must contain only lower-case ASCII letters, | |||
| // ASCII digits, dots (U+002E), and dashes (U+002D); | |||
| @@ -279,8 +295,9 @@ func fileNameOK(r rune) bool { | |||
| // and must not contain any dots. For paths beginning with "gopkg.in/", | |||
| // this second requirement is replaced by a requirement that the path | |||
| // follow the gopkg.in server's conventions. | |||
| // Third, no path element may begin with a dot. | |||
| func CheckPath(path string) error { | |||
| if err := checkPath(path, false); err != nil { | |||
| if err := checkPath(path, modulePath); err != nil { | |||
| return fmt.Errorf("malformed module path %q: %v", path, err) | |||
| } | |||
| i := strings.Index(path, "/") | |||
| @@ -313,29 +330,41 @@ func CheckPath(path string) error { | |||
| // separated by slashes (U+002F). (It must not begin with nor end in a slash.) | |||
| // | |||
| // A valid path element is a non-empty string made up of | |||
| // ASCII letters, ASCII digits, and limited ASCII punctuation: + - . _ and ~. | |||
| // It must not begin or end with a dot (U+002E), nor contain two dots in a row. | |||
| // ASCII letters, ASCII digits, and limited ASCII punctuation: - . _ and ~. | |||
| // It must not end with a dot (U+002E), nor contain two dots in a row. | |||
| // | |||
| // The element prefix up to the first dot must not be a reserved file name | |||
| // on Windows, regardless of case (CON, com1, NuL, and so on). | |||
| // on Windows, regardless of case (CON, com1, NuL, and so on). The element | |||
| // must not have a suffix of a tilde followed by one or more ASCII digits | |||
| // (to exclude paths elements that look like Windows short-names). | |||
| // | |||
| // CheckImportPath may be less restrictive in the future, but see the | |||
| // top-level package documentation for additional information about | |||
| // subtleties of Unicode. | |||
| func CheckImportPath(path string) error { | |||
| if err := checkPath(path, false); err != nil { | |||
| if err := checkPath(path, importPath); err != nil { | |||
| return fmt.Errorf("malformed import path %q: %v", path, err) | |||
| } | |||
| return nil | |||
| } | |||
| // pathKind indicates what kind of path we're checking. Module paths, | |||
| // import paths, and file paths have different restrictions. | |||
| type pathKind int | |||
| const ( | |||
| modulePath pathKind = iota | |||
| importPath | |||
| filePath | |||
| ) | |||
| // checkPath checks that a general path is valid. | |||
| // It returns an error describing why but not mentioning path. | |||
| // Because these checks apply to both module paths and import paths, | |||
| // the caller is expected to add the "malformed ___ path %q: " prefix. | |||
| // fileName indicates whether the final element of the path is a file name | |||
| // (as opposed to a directory name). | |||
| func checkPath(path string, fileName bool) error { | |||
| func checkPath(path string, kind pathKind) error { | |||
| if !utf8.ValidString(path) { | |||
| return fmt.Errorf("invalid UTF-8") | |||
| } | |||
| @@ -354,39 +383,45 @@ func checkPath(path string, fileName bool) error { | |||
| elemStart := 0 | |||
| for i, r := range path { | |||
| if r == '/' { | |||
| if err := checkElem(path[elemStart:i], fileName); err != nil { | |||
| if err := checkElem(path[elemStart:i], kind); err != nil { | |||
| return err | |||
| } | |||
| elemStart = i + 1 | |||
| } | |||
| } | |||
| if err := checkElem(path[elemStart:], fileName); err != nil { | |||
| if err := checkElem(path[elemStart:], kind); err != nil { | |||
| return err | |||
| } | |||
| return nil | |||
| } | |||
| // checkElem checks whether an individual path element is valid. | |||
| // fileName indicates whether the element is a file name (not a directory name). | |||
| func checkElem(elem string, fileName bool) error { | |||
| func checkElem(elem string, kind pathKind) error { | |||
| if elem == "" { | |||
| return fmt.Errorf("empty path element") | |||
| } | |||
| if strings.Count(elem, ".") == len(elem) { | |||
| return fmt.Errorf("invalid path element %q", elem) | |||
| } | |||
| if elem[0] == '.' && !fileName { | |||
| if elem[0] == '.' && kind == modulePath { | |||
| return fmt.Errorf("leading dot in path element") | |||
| } | |||
| if elem[len(elem)-1] == '.' { | |||
| return fmt.Errorf("trailing dot in path element") | |||
| } | |||
| charOK := pathOK | |||
| if fileName { | |||
| charOK = fileNameOK | |||
| } | |||
| for _, r := range elem { | |||
| if !charOK(r) { | |||
| ok := false | |||
| switch kind { | |||
| case modulePath: | |||
| ok = modPathOK(r) | |||
| case importPath: | |||
| ok = importPathOK(r) | |||
| case filePath: | |||
| ok = fileNameOK(r) | |||
| default: | |||
| panic(fmt.Sprintf("internal error: invalid kind %v", kind)) | |||
| } | |||
| if !ok { | |||
| return fmt.Errorf("invalid char %q", r) | |||
| } | |||
| } | |||
| @@ -402,6 +437,29 @@ func checkElem(elem string, fileName bool) error { | |||
| return fmt.Errorf("%q disallowed as path element component on Windows", short) | |||
| } | |||
| } | |||
| if kind == filePath { | |||
| // don't check for Windows short-names in file names. They're | |||
| // only an issue for import paths. | |||
| return nil | |||
| } | |||
| // Reject path components that look like Windows short-names. | |||
| // Those usually end in a tilde followed by one or more ASCII digits. | |||
| if tilde := strings.LastIndexByte(short, '~'); tilde >= 0 && tilde < len(short)-1 { | |||
| suffix := short[tilde+1:] | |||
| suffixIsDigits := true | |||
| for _, r := range suffix { | |||
| if r < '0' || r > '9' { | |||
| suffixIsDigits = false | |||
| break | |||
| } | |||
| } | |||
| if suffixIsDigits { | |||
| return fmt.Errorf("trailing tilde and digits in path element") | |||
| } | |||
| } | |||
| return nil | |||
| } | |||
| @@ -418,7 +476,7 @@ func checkElem(elem string, fileName bool) error { | |||
| // top-level package documentation for additional information about | |||
| // subtleties of Unicode. | |||
| func CheckFilePath(path string) error { | |||
| if err := checkPath(path, true); err != nil { | |||
| if err := checkPath(path, filePath); err != nil { | |||
| return fmt.Errorf("malformed file path %q: %v", path, err) | |||
| } | |||
| return nil | |||
| @@ -621,7 +679,7 @@ func EscapePath(path string) (escaped string, err error) { | |||
| // Versions are allowed to be in non-semver form but must be valid file names | |||
| // and not contain exclamation marks. | |||
| func EscapeVersion(v string) (escaped string, err error) { | |||
| if err := checkElem(v, true); err != nil || strings.Contains(v, "!") { | |||
| if err := checkElem(v, filePath); err != nil || strings.Contains(v, "!") { | |||
| return "", &InvalidVersionError{ | |||
| Version: v, | |||
| Err: fmt.Errorf("disallowed version string"), | |||
| @@ -680,7 +738,7 @@ func UnescapeVersion(escaped string) (v string, err error) { | |||
| if !ok { | |||
| return "", fmt.Errorf("invalid escaped version %q", escaped) | |||
| } | |||
| if err := checkElem(v, true); err != nil { | |||
| if err := checkElem(v, filePath); err != nil { | |||
| return "", fmt.Errorf("invalid escaped version %q: %v", v, err) | |||
| } | |||
| return v, nil | |||
| @@ -716,3 +774,49 @@ func unescapeString(escaped string) (string, bool) { | |||
| } | |||
| return string(buf), true | |||
| } | |||
| // MatchPrefixPatterns reports whether any path prefix of target matches one of | |||
| // the glob patterns (as defined by path.Match) in the comma-separated globs | |||
| // list. This implements the algorithm used when matching a module path to the | |||
| // GOPRIVATE environment variable, as described by 'go help module-private'. | |||
| // | |||
| // It ignores any empty or malformed patterns in the list. | |||
| func MatchPrefixPatterns(globs, target string) bool { | |||
| for globs != "" { | |||
| // Extract next non-empty glob in comma-separated list. | |||
| var glob string | |||
| if i := strings.Index(globs, ","); i >= 0 { | |||
| glob, globs = globs[:i], globs[i+1:] | |||
| } else { | |||
| glob, globs = globs, "" | |||
| } | |||
| if glob == "" { | |||
| continue | |||
| } | |||
| // A glob with N+1 path elements (N slashes) needs to be matched | |||
| // against the first N+1 path elements of target, | |||
| // which end just before the N+1'th slash. | |||
| n := strings.Count(glob, "/") | |||
| prefix := target | |||
| // Walk target, counting slashes, truncating at the N+1'th slash. | |||
| for i := 0; i < len(target); i++ { | |||
| if target[i] == '/' { | |||
| if n == 0 { | |||
| prefix = target[:i] | |||
| break | |||
| } | |||
| n-- | |||
| } | |||
| } | |||
| if n > 0 { | |||
| // Not enough prefix elements. | |||
| continue | |||
| } | |||
| matched, _ := path.Match(glob, prefix) | |||
| if matched { | |||
| return true | |||
| } | |||
| } | |||
| return false | |||
| } | |||
| @@ -138,6 +138,9 @@ func Compare(v, w string) int { | |||
| // Max canonicalizes its arguments and then returns the version string | |||
| // that compares greater. | |||
| // | |||
| // Deprecated: use Compare instead. In most cases, returning a canonicalized | |||
| // version is not expected or desired. | |||
| func Max(v, w string) string { | |||
| v = Canonical(v) | |||
| w = Canonical(w) | |||
| @@ -2,6 +2,7 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build go1.7 | |||
| // +build go1.7 | |||
| package context | |||
| @@ -2,6 +2,7 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build go1.9 | |||
| // +build go1.9 | |||
| package context | |||
| @@ -2,6 +2,7 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build !go1.7 | |||
| // +build !go1.7 | |||
| package context | |||
| @@ -2,6 +2,7 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build !go1.9 | |||
| // +build !go1.9 | |||
| package context | |||
| @@ -52,7 +52,7 @@ var isSpecialElementMap = map[string]bool{ | |||
| "iframe": true, | |||
| "img": true, | |||
| "input": true, | |||
| "keygen": true, | |||
| "keygen": true, // "keygen" has been removed from the spec, but are kept here for backwards compatibility. | |||
| "li": true, | |||
| "link": true, | |||
| "listing": true, | |||
| @@ -161,65 +161,62 @@ var mathMLAttributeAdjustments = map[string]string{ | |||
| } | |||
| var svgAttributeAdjustments = map[string]string{ | |||
| "attributename": "attributeName", | |||
| "attributetype": "attributeType", | |||
| "basefrequency": "baseFrequency", | |||
| "baseprofile": "baseProfile", | |||
| "calcmode": "calcMode", | |||
| "clippathunits": "clipPathUnits", | |||
| "contentscripttype": "contentScriptType", | |||
| "contentstyletype": "contentStyleType", | |||
| "diffuseconstant": "diffuseConstant", | |||
| "edgemode": "edgeMode", | |||
| "externalresourcesrequired": "externalResourcesRequired", | |||
| "filterunits": "filterUnits", | |||
| "glyphref": "glyphRef", | |||
| "gradienttransform": "gradientTransform", | |||
| "gradientunits": "gradientUnits", | |||
| "kernelmatrix": "kernelMatrix", | |||
| "kernelunitlength": "kernelUnitLength", | |||
| "keypoints": "keyPoints", | |||
| "keysplines": "keySplines", | |||
| "keytimes": "keyTimes", | |||
| "lengthadjust": "lengthAdjust", | |||
| "limitingconeangle": "limitingConeAngle", | |||
| "markerheight": "markerHeight", | |||
| "markerunits": "markerUnits", | |||
| "markerwidth": "markerWidth", | |||
| "maskcontentunits": "maskContentUnits", | |||
| "maskunits": "maskUnits", | |||
| "numoctaves": "numOctaves", | |||
| "pathlength": "pathLength", | |||
| "patterncontentunits": "patternContentUnits", | |||
| "patterntransform": "patternTransform", | |||
| "patternunits": "patternUnits", | |||
| "pointsatx": "pointsAtX", | |||
| "pointsaty": "pointsAtY", | |||
| "pointsatz": "pointsAtZ", | |||
| "preservealpha": "preserveAlpha", | |||
| "preserveaspectratio": "preserveAspectRatio", | |||
| "primitiveunits": "primitiveUnits", | |||
| "refx": "refX", | |||
| "refy": "refY", | |||
| "repeatcount": "repeatCount", | |||
| "repeatdur": "repeatDur", | |||
| "requiredextensions": "requiredExtensions", | |||
| "requiredfeatures": "requiredFeatures", | |||
| "specularconstant": "specularConstant", | |||
| "specularexponent": "specularExponent", | |||
| "spreadmethod": "spreadMethod", | |||
| "startoffset": "startOffset", | |||
| "stddeviation": "stdDeviation", | |||
| "stitchtiles": "stitchTiles", | |||
| "surfacescale": "surfaceScale", | |||
| "systemlanguage": "systemLanguage", | |||
| "tablevalues": "tableValues", | |||
| "targetx": "targetX", | |||
| "targety": "targetY", | |||
| "textlength": "textLength", | |||
| "viewbox": "viewBox", | |||
| "viewtarget": "viewTarget", | |||
| "xchannelselector": "xChannelSelector", | |||
| "ychannelselector": "yChannelSelector", | |||
| "zoomandpan": "zoomAndPan", | |||
| "attributename": "attributeName", | |||
| "attributetype": "attributeType", | |||
| "basefrequency": "baseFrequency", | |||
| "baseprofile": "baseProfile", | |||
| "calcmode": "calcMode", | |||
| "clippathunits": "clipPathUnits", | |||
| "diffuseconstant": "diffuseConstant", | |||
| "edgemode": "edgeMode", | |||
| "filterunits": "filterUnits", | |||
| "glyphref": "glyphRef", | |||
| "gradienttransform": "gradientTransform", | |||
| "gradientunits": "gradientUnits", | |||
| "kernelmatrix": "kernelMatrix", | |||
| "kernelunitlength": "kernelUnitLength", | |||
| "keypoints": "keyPoints", | |||
| "keysplines": "keySplines", | |||
| "keytimes": "keyTimes", | |||
| "lengthadjust": "lengthAdjust", | |||
| "limitingconeangle": "limitingConeAngle", | |||
| "markerheight": "markerHeight", | |||
| "markerunits": "markerUnits", | |||
| "markerwidth": "markerWidth", | |||
| "maskcontentunits": "maskContentUnits", | |||
| "maskunits": "maskUnits", | |||
| "numoctaves": "numOctaves", | |||
| "pathlength": "pathLength", | |||
| "patterncontentunits": "patternContentUnits", | |||
| "patterntransform": "patternTransform", | |||
| "patternunits": "patternUnits", | |||
| "pointsatx": "pointsAtX", | |||
| "pointsaty": "pointsAtY", | |||
| "pointsatz": "pointsAtZ", | |||
| "preservealpha": "preserveAlpha", | |||
| "preserveaspectratio": "preserveAspectRatio", | |||
| "primitiveunits": "primitiveUnits", | |||
| "refx": "refX", | |||
| "refy": "refY", | |||
| "repeatcount": "repeatCount", | |||
| "repeatdur": "repeatDur", | |||
| "requiredextensions": "requiredExtensions", | |||
| "requiredfeatures": "requiredFeatures", | |||
| "specularconstant": "specularConstant", | |||
| "specularexponent": "specularExponent", | |||
| "spreadmethod": "spreadMethod", | |||
| "startoffset": "startOffset", | |||
| "stddeviation": "stdDeviation", | |||
| "stitchtiles": "stitchTiles", | |||
| "surfacescale": "surfaceScale", | |||
| "systemlanguage": "systemLanguage", | |||
| "tablevalues": "tableValues", | |||
| "targetx": "targetX", | |||
| "targety": "targetY", | |||
| "textlength": "textLength", | |||
| "viewbox": "viewBox", | |||
| "viewtarget": "viewTarget", | |||
| "xchannelselector": "xChannelSelector", | |||
| "ychannelselector": "yChannelSelector", | |||
| "zoomandpan": "zoomAndPan", | |||
| } | |||
| @@ -728,7 +728,13 @@ func inHeadNoscriptIM(p *parser) bool { | |||
| return inBodyIM(p) | |||
| case a.Basefont, a.Bgsound, a.Link, a.Meta, a.Noframes, a.Style: | |||
| return inHeadIM(p) | |||
| case a.Head, a.Noscript: | |||
| case a.Head: | |||
| // Ignore the token. | |||
| return true | |||
| case a.Noscript: | |||
| // Don't let the tokenizer go into raw text mode even when a <noscript> | |||
| // tag is in "in head noscript" insertion mode. | |||
| p.tokenizer.NextIsNotRawText() | |||
| // Ignore the token. | |||
| return true | |||
| } | |||
| @@ -1790,6 +1796,13 @@ func inSelectIM(p *parser) bool { | |||
| return true | |||
| case a.Script, a.Template: | |||
| return inHeadIM(p) | |||
| case a.Iframe, a.Noembed, a.Noframes, a.Noscript, a.Plaintext, a.Style, a.Title, a.Xmp: | |||
| // Don't let the tokenizer go into raw text mode when there are raw tags | |||
| // to be ignored. These tags should be ignored from the tokenizer | |||
| // properly. | |||
| p.tokenizer.NextIsNotRawText() | |||
| // Ignore the token. | |||
| return true | |||
| } | |||
| case EndTagToken: | |||
| switch p.tok.DataAtom { | |||
| @@ -263,7 +263,7 @@ var voidElements = map[string]bool{ | |||
| "hr": true, | |||
| "img": true, | |||
| "input": true, | |||
| "keygen": true, | |||
| "keygen": true, // "keygen" has been removed from the spec, but are kept here for backwards compatibility. | |||
| "link": true, | |||
| "meta": true, | |||
| "param": true, | |||
| @@ -2,6 +2,7 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build go1.11 | |||
| // +build go1.11 | |||
| package http2 | |||
| @@ -2,6 +2,7 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build !go1.11 | |||
| // +build !go1.11 | |||
| package http2 | |||
| @@ -1293,7 +1293,9 @@ func (sc *serverConn) startGracefulShutdown() { | |||
| sc.shutdownOnce.Do(func() { sc.sendServeMsg(gracefulShutdownMsg) }) | |||
| } | |||
| // After sending GOAWAY, the connection will close after goAwayTimeout. | |||
| // After sending GOAWAY with an error code (non-graceful shutdown), the | |||
| // connection will close after goAwayTimeout. | |||
| // | |||
| // If we close the connection immediately after sending GOAWAY, there may | |||
| // be unsent data in our kernel receive buffer, which will cause the kernel | |||
| // to send a TCP RST on close() instead of a FIN. This RST will abort the | |||
| @@ -1629,23 +1631,37 @@ func (sc *serverConn) processSettingInitialWindowSize(val uint32) error { | |||
| func (sc *serverConn) processData(f *DataFrame) error { | |||
| sc.serveG.check() | |||
| if sc.inGoAway && sc.goAwayCode != ErrCodeNo { | |||
| id := f.Header().StreamID | |||
| if sc.inGoAway && (sc.goAwayCode != ErrCodeNo || id > sc.maxClientStreamID) { | |||
| // Discard all DATA frames if the GOAWAY is due to an | |||
| // error, or: | |||
| // | |||
| // Section 6.8: After sending a GOAWAY frame, the sender | |||
| // can discard frames for streams initiated by the | |||
| // receiver with identifiers higher than the identified | |||
| // last stream. | |||
| return nil | |||
| } | |||
| data := f.Data() | |||
| // "If a DATA frame is received whose stream is not in "open" | |||
| // or "half closed (local)" state, the recipient MUST respond | |||
| // with a stream error (Section 5.4.2) of type STREAM_CLOSED." | |||
| id := f.Header().StreamID | |||
| data := f.Data() | |||
| state, st := sc.state(id) | |||
| if id == 0 || state == stateIdle { | |||
| // Section 6.1: "DATA frames MUST be associated with a | |||
| // stream. If a DATA frame is received whose stream | |||
| // identifier field is 0x0, the recipient MUST respond | |||
| // with a connection error (Section 5.4.1) of type | |||
| // PROTOCOL_ERROR." | |||
| // | |||
| // Section 5.1: "Receiving any frame other than HEADERS | |||
| // or PRIORITY on a stream in this state MUST be | |||
| // treated as a connection error (Section 5.4.1) of | |||
| // type PROTOCOL_ERROR." | |||
| return ConnectionError(ErrCodeProtocol) | |||
| } | |||
| // "If a DATA frame is received whose stream is not in "open" | |||
| // or "half closed (local)" state, the recipient MUST respond | |||
| // with a stream error (Section 5.4.2) of type STREAM_CLOSED." | |||
| if st == nil || state != stateOpen || st.gotTrailerHeader || st.resetQueued { | |||
| // This includes sending a RST_STREAM if the stream is | |||
| // in stateHalfClosedLocal (which currently means that | |||
| @@ -1694,6 +1710,7 @@ func (sc *serverConn) processData(f *DataFrame) error { | |||
| if len(data) > 0 { | |||
| wrote, err := st.body.Write(data) | |||
| if err != nil { | |||
| sc.sendWindowUpdate(nil, int(f.Length)-wrote) | |||
| return streamError(id, ErrCodeStreamClosed) | |||
| } | |||
| if wrote != len(data) { | |||
| @@ -2020,7 +2037,11 @@ func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*res | |||
| } | |||
| if bodyOpen { | |||
| if vv, ok := rp.header["Content-Length"]; ok { | |||
| req.ContentLength, _ = strconv.ParseInt(vv[0], 10, 64) | |||
| if cl, err := strconv.ParseUint(vv[0], 10, 63); err == nil { | |||
| req.ContentLength = int64(cl) | |||
| } else { | |||
| req.ContentLength = 0 | |||
| } | |||
| } else { | |||
| req.ContentLength = -1 | |||
| } | |||
| @@ -2403,9 +2424,8 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) { | |||
| var ctype, clen string | |||
| if clen = rws.snapHeader.Get("Content-Length"); clen != "" { | |||
| rws.snapHeader.Del("Content-Length") | |||
| clen64, err := strconv.ParseInt(clen, 10, 64) | |||
| if err == nil && clen64 >= 0 { | |||
| rws.sentContentLen = clen64 | |||
| if cl, err := strconv.ParseUint(clen, 10, 63); err == nil { | |||
| rws.sentContentLen = int64(cl) | |||
| } else { | |||
| clen = "" | |||
| } | |||
| @@ -108,6 +108,19 @@ type Transport struct { | |||
| // waiting for their turn. | |||
| StrictMaxConcurrentStreams bool | |||
| // ReadIdleTimeout is the timeout after which a health check using ping | |||
| // frame will be carried out if no frame is received on the connection. | |||
| // Note that a ping response will is considered a received frame, so if | |||
| // there is no other traffic on the connection, the health check will | |||
| // be performed every ReadIdleTimeout interval. | |||
| // If zero, no health check is performed. | |||
| ReadIdleTimeout time.Duration | |||
| // PingTimeout is the timeout after which the connection will be closed | |||
| // if a response to Ping is not received. | |||
| // Defaults to 15s. | |||
| PingTimeout time.Duration | |||
| // t1, if non-nil, is the standard library Transport using | |||
| // this transport. Its settings are used (but not its | |||
| // RoundTrip method, etc). | |||
| @@ -131,14 +144,31 @@ func (t *Transport) disableCompression() bool { | |||
| return t.DisableCompression || (t.t1 != nil && t.t1.DisableCompression) | |||
| } | |||
| func (t *Transport) pingTimeout() time.Duration { | |||
| if t.PingTimeout == 0 { | |||
| return 15 * time.Second | |||
| } | |||
| return t.PingTimeout | |||
| } | |||
| // ConfigureTransport configures a net/http HTTP/1 Transport to use HTTP/2. | |||
| // It returns an error if t1 has already been HTTP/2-enabled. | |||
| // | |||
| // Use ConfigureTransports instead to configure the HTTP/2 Transport. | |||
| func ConfigureTransport(t1 *http.Transport) error { | |||
| _, err := configureTransport(t1) | |||
| _, err := ConfigureTransports(t1) | |||
| return err | |||
| } | |||
| func configureTransport(t1 *http.Transport) (*Transport, error) { | |||
| // ConfigureTransports configures a net/http HTTP/1 Transport to use HTTP/2. | |||
| // It returns a new HTTP/2 Transport for further configuration. | |||
| // It returns an error if t1 has already been HTTP/2-enabled. | |||
| func ConfigureTransports(t1 *http.Transport) (*Transport, error) { | |||
| return configureTransports(t1) | |||
| } | |||
| func configureTransports(t1 *http.Transport) (*Transport, error) { | |||
| connPool := new(clientConnPool) | |||
| t2 := &Transport{ | |||
| ConnPool: noDialClientConnPool{connPool}, | |||
| @@ -668,6 +698,7 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, erro | |||
| cc.inflow.add(transportDefaultConnFlow + initialWindowSize) | |||
| cc.bw.Flush() | |||
| if cc.werr != nil { | |||
| cc.Close() | |||
| return nil, cc.werr | |||
| } | |||
| @@ -675,6 +706,20 @@ func (t *Transport) newClientConn(c net.Conn, singleUse bool) (*ClientConn, erro | |||
| return cc, nil | |||
| } | |||
| func (cc *ClientConn) healthCheck() { | |||
| pingTimeout := cc.t.pingTimeout() | |||
| // We don't need to periodically ping in the health check, because the readLoop of ClientConn will | |||
| // trigger the healthCheck again if there is no frame received. | |||
| ctx, cancel := context.WithTimeout(context.Background(), pingTimeout) | |||
| defer cancel() | |||
| err := cc.Ping(ctx) | |||
| if err != nil { | |||
| cc.closeForLostPing() | |||
| cc.t.connPool().MarkDead(cc) | |||
| return | |||
| } | |||
| } | |||
| func (cc *ClientConn) setGoAway(f *GoAwayFrame) { | |||
| cc.mu.Lock() | |||
| defer cc.mu.Unlock() | |||
| @@ -846,14 +891,12 @@ func (cc *ClientConn) sendGoAway() error { | |||
| return nil | |||
| } | |||
| // Close closes the client connection immediately. | |||
| // | |||
| // In-flight requests are interrupted. For a graceful shutdown, use Shutdown instead. | |||
| func (cc *ClientConn) Close() error { | |||
| // closes the client connection immediately. In-flight requests are interrupted. | |||
| // err is sent to streams. | |||
| func (cc *ClientConn) closeForError(err error) error { | |||
| cc.mu.Lock() | |||
| defer cc.cond.Broadcast() | |||
| defer cc.mu.Unlock() | |||
| err := errors.New("http2: client connection force closed via ClientConn.Close") | |||
| for id, cs := range cc.streams { | |||
| select { | |||
| case cs.resc <- resAndError{err: err}: | |||
| @@ -866,6 +909,20 @@ func (cc *ClientConn) Close() error { | |||
| return cc.tconn.Close() | |||
| } | |||
| // Close closes the client connection immediately. | |||
| // | |||
| // In-flight requests are interrupted. For a graceful shutdown, use Shutdown instead. | |||
| func (cc *ClientConn) Close() error { | |||
| err := errors.New("http2: client connection force closed via ClientConn.Close") | |||
| return cc.closeForError(err) | |||
| } | |||
| // closes the client connection immediately. In-flight requests are interrupted. | |||
| func (cc *ClientConn) closeForLostPing() error { | |||
| err := errors.New("http2: client connection lost") | |||
| return cc.closeForError(err) | |||
| } | |||
| const maxAllocFrameSize = 512 << 10 | |||
| // frameBuffer returns a scratch buffer suitable for writing DATA frames. | |||
| @@ -1033,6 +1090,15 @@ func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAf | |||
| bodyWriter := cc.t.getBodyWriterState(cs, body) | |||
| cs.on100 = bodyWriter.on100 | |||
| defer func() { | |||
| cc.wmu.Lock() | |||
| werr := cc.werr | |||
| cc.wmu.Unlock() | |||
| if werr != nil { | |||
| cc.Close() | |||
| } | |||
| }() | |||
| cc.wmu.Lock() | |||
| endStream := !hasBody && !hasTrailers | |||
| werr := cc.writeHeaders(cs.ID, endStream, int(cc.maxFrameSize), hdrs) | |||
| @@ -1082,6 +1148,9 @@ func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAf | |||
| // we can keep it. | |||
| bodyWriter.cancel() | |||
| cs.abortRequestBodyWrite(errStopReqBodyWrite) | |||
| if hasBody && !bodyWritten { | |||
| <-bodyWriter.resc | |||
| } | |||
| } | |||
| if re.err != nil { | |||
| cc.forgetStreamID(cs.ID) | |||
| @@ -1102,6 +1171,7 @@ func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAf | |||
| } else { | |||
| bodyWriter.cancel() | |||
| cs.abortRequestBodyWrite(errStopReqBodyWriteAndCancel) | |||
| <-bodyWriter.resc | |||
| } | |||
| cc.forgetStreamID(cs.ID) | |||
| return nil, cs.getStartedWrite(), errTimeout | |||
| @@ -1111,6 +1181,7 @@ func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAf | |||
| } else { | |||
| bodyWriter.cancel() | |||
| cs.abortRequestBodyWrite(errStopReqBodyWriteAndCancel) | |||
| <-bodyWriter.resc | |||
| } | |||
| cc.forgetStreamID(cs.ID) | |||
| return nil, cs.getStartedWrite(), ctx.Err() | |||
| @@ -1120,6 +1191,7 @@ func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAf | |||
| } else { | |||
| bodyWriter.cancel() | |||
| cs.abortRequestBodyWrite(errStopReqBodyWriteAndCancel) | |||
| <-bodyWriter.resc | |||
| } | |||
| cc.forgetStreamID(cs.ID) | |||
| return nil, cs.getStartedWrite(), errRequestCanceled | |||
| @@ -1129,6 +1201,7 @@ func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAf | |||
| // forgetStreamID. | |||
| return nil, cs.getStartedWrite(), cs.resetErr | |||
| case err := <-bodyWriter.resc: | |||
| bodyWritten = true | |||
| // Prefer the read loop's response, if available. Issue 16102. | |||
| select { | |||
| case re := <-readLoopResCh: | |||
| @@ -1139,7 +1212,6 @@ func (cc *ClientConn) roundTrip(req *http.Request) (res *http.Response, gotErrAf | |||
| cc.forgetStreamID(cs.ID) | |||
| return nil, cs.getStartedWrite(), err | |||
| } | |||
| bodyWritten = true | |||
| if d := cc.responseHeaderTimeout(); d != 0 { | |||
| timer := time.NewTimer(d) | |||
| defer timer.Stop() | |||
| @@ -1737,8 +1809,17 @@ func (rl *clientConnReadLoop) run() error { | |||
| rl.closeWhenIdle = cc.t.disableKeepAlives() || cc.singleUse | |||
| gotReply := false // ever saw a HEADERS reply | |||
| gotSettings := false | |||
| readIdleTimeout := cc.t.ReadIdleTimeout | |||
| var t *time.Timer | |||
| if readIdleTimeout != 0 { | |||
| t = time.AfterFunc(readIdleTimeout, cc.healthCheck) | |||
| defer t.Stop() | |||
| } | |||
| for { | |||
| f, err := cc.fr.ReadFrame() | |||
| if t != nil { | |||
| t.Reset(readIdleTimeout) | |||
| } | |||
| if err != nil { | |||
| cc.vlogf("http2: Transport readFrame error on conn %p: (%T) %v", cc, err, err) | |||
| } | |||
| @@ -1950,8 +2031,8 @@ func (rl *clientConnReadLoop) handleResponse(cs *clientStream, f *MetaHeadersFra | |||
| if !streamEnded || isHead { | |||
| res.ContentLength = -1 | |||
| if clens := res.Header["Content-Length"]; len(clens) == 1 { | |||
| if clen64, err := strconv.ParseInt(clens[0], 10, 64); err == nil { | |||
| res.ContentLength = clen64 | |||
| if cl, err := strconv.ParseUint(clens[0], 10, 63); err == nil { | |||
| res.ContentLength = int64(cl) | |||
| } else { | |||
| // TODO: care? unlike http/1, it won't mess up our framing, so it's | |||
| // more safe smuggling-wise to ignore. | |||
| @@ -2469,6 +2550,7 @@ func strSliceContains(ss []string, s string) bool { | |||
| type erringRoundTripper struct{ err error } | |||
| func (rt erringRoundTripper) RoundTripErr() error { return rt.err } | |||
| func (rt erringRoundTripper) RoundTrip(*http.Request) (*http.Response, error) { return nil, rt.err } | |||
| // gzipReader wraps a response body so it can lazily | |||
| @@ -2550,7 +2632,9 @@ func (t *Transport) getBodyWriterState(cs *clientStream, body io.Reader) (s body | |||
| func (s bodyWriterState) cancel() { | |||
| if s.timer != nil { | |||
| s.timer.Stop() | |||
| if s.timer.Stop() { | |||
| s.resc <- nil | |||
| } | |||
| } | |||
| } | |||
| @@ -4,6 +4,7 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build go1.10 | |||
| // +build go1.10 | |||
| // Package idna implements IDNA2008 using the compatibility processing | |||
| @@ -4,6 +4,7 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build !go1.10 | |||
| // +build !go1.10 | |||
| // Package idna implements IDNA2008 using the compatibility processing | |||
| @@ -1,5 +1,6 @@ | |||
| // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. | |||
| //go:build go1.10 && !go1.13 | |||
| // +build go1.10,!go1.13 | |||
| package idna | |||
| @@ -1,5 +1,6 @@ | |||
| // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. | |||
| //go:build go1.13 && !go1.14 | |||
| // +build go1.13,!go1.14 | |||
| package idna | |||
| @@ -1,6 +1,7 @@ | |||
| // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. | |||
| // +build go1.14 | |||
| //go:build go1.14 && !go1.16 | |||
| // +build go1.14,!go1.16 | |||
| package idna | |||
| @@ -1,5 +1,6 @@ | |||
| // Code generated by running "go generate" in golang.org/x/text. DO NOT EDIT. | |||
| //go:build !go1.10 | |||
| // +build !go1.10 | |||
| package idna | |||
| @@ -2,7 +2,8 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !gccgo | |||
| //go:build gc | |||
| // +build gc | |||
| #include "textflag.h" | |||
| @@ -39,20 +39,25 @@ func (bigEndian) Uint64(b []byte) uint64 { | |||
| uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56 | |||
| } | |||
| // hostByteOrder returns binary.LittleEndian on little-endian machines and | |||
| // binary.BigEndian on big-endian machines. | |||
| // hostByteOrder returns littleEndian on little-endian machines and | |||
| // bigEndian on big-endian machines. | |||
| func hostByteOrder() byteOrder { | |||
| switch runtime.GOARCH { | |||
| case "386", "amd64", "amd64p32", | |||
| "alpha", | |||
| "arm", "arm64", | |||
| "mipsle", "mips64le", "mips64p32le", | |||
| "nios2", | |||
| "ppc64le", | |||
| "riscv", "riscv64": | |||
| "riscv", "riscv64", | |||
| "sh": | |||
| return littleEndian{} | |||
| case "armbe", "arm64be", | |||
| "m68k", | |||
| "mips", "mips64", "mips64p32", | |||
| "ppc", "ppc64", | |||
| "s390", "s390x", | |||
| "shbe", | |||
| "sparc", "sparc64": | |||
| return bigEndian{} | |||
| } | |||
| @@ -6,6 +6,11 @@ | |||
| // various CPU architectures. | |||
| package cpu | |||
| import ( | |||
| "os" | |||
| "strings" | |||
| ) | |||
| // Initialized reports whether the CPU features were initialized. | |||
| // | |||
| // For some GOOS/GOARCH combinations initialization of the CPU features depends | |||
| @@ -24,26 +29,46 @@ type CacheLinePad struct{ _ [cacheLineSize]byte } | |||
| // and HasAVX2 are only set if the OS supports XMM and YMM | |||
| // registers in addition to the CPUID feature bit being set. | |||
| var X86 struct { | |||
| _ CacheLinePad | |||
| HasAES bool // AES hardware implementation (AES NI) | |||
| HasADX bool // Multi-precision add-carry instruction extensions | |||
| HasAVX bool // Advanced vector extension | |||
| HasAVX2 bool // Advanced vector extension 2 | |||
| HasBMI1 bool // Bit manipulation instruction set 1 | |||
| HasBMI2 bool // Bit manipulation instruction set 2 | |||
| HasERMS bool // Enhanced REP for MOVSB and STOSB | |||
| HasFMA bool // Fused-multiply-add instructions | |||
| HasOSXSAVE bool // OS supports XSAVE/XRESTOR for saving/restoring XMM registers. | |||
| HasPCLMULQDQ bool // PCLMULQDQ instruction - most often used for AES-GCM | |||
| HasPOPCNT bool // Hamming weight instruction POPCNT. | |||
| HasRDRAND bool // RDRAND instruction (on-chip random number generator) | |||
| HasRDSEED bool // RDSEED instruction (on-chip random number generator) | |||
| HasSSE2 bool // Streaming SIMD extension 2 (always available on amd64) | |||
| HasSSE3 bool // Streaming SIMD extension 3 | |||
| HasSSSE3 bool // Supplemental streaming SIMD extension 3 | |||
| HasSSE41 bool // Streaming SIMD extension 4 and 4.1 | |||
| HasSSE42 bool // Streaming SIMD extension 4 and 4.2 | |||
| _ CacheLinePad | |||
| _ CacheLinePad | |||
| HasAES bool // AES hardware implementation (AES NI) | |||
| HasADX bool // Multi-precision add-carry instruction extensions | |||
| HasAVX bool // Advanced vector extension | |||
| HasAVX2 bool // Advanced vector extension 2 | |||
| HasAVX512 bool // Advanced vector extension 512 | |||
| HasAVX512F bool // Advanced vector extension 512 Foundation Instructions | |||
| HasAVX512CD bool // Advanced vector extension 512 Conflict Detection Instructions | |||
| HasAVX512ER bool // Advanced vector extension 512 Exponential and Reciprocal Instructions | |||
| HasAVX512PF bool // Advanced vector extension 512 Prefetch Instructions Instructions | |||
| HasAVX512VL bool // Advanced vector extension 512 Vector Length Extensions | |||
| HasAVX512BW bool // Advanced vector extension 512 Byte and Word Instructions | |||
| HasAVX512DQ bool // Advanced vector extension 512 Doubleword and Quadword Instructions | |||
| HasAVX512IFMA bool // Advanced vector extension 512 Integer Fused Multiply Add | |||
| HasAVX512VBMI bool // Advanced vector extension 512 Vector Byte Manipulation Instructions | |||
| HasAVX5124VNNIW bool // Advanced vector extension 512 Vector Neural Network Instructions Word variable precision | |||
| HasAVX5124FMAPS bool // Advanced vector extension 512 Fused Multiply Accumulation Packed Single precision | |||
| HasAVX512VPOPCNTDQ bool // Advanced vector extension 512 Double and quad word population count instructions | |||
| HasAVX512VPCLMULQDQ bool // Advanced vector extension 512 Vector carry-less multiply operations | |||
| HasAVX512VNNI bool // Advanced vector extension 512 Vector Neural Network Instructions | |||
| HasAVX512GFNI bool // Advanced vector extension 512 Galois field New Instructions | |||
| HasAVX512VAES bool // Advanced vector extension 512 Vector AES instructions | |||
| HasAVX512VBMI2 bool // Advanced vector extension 512 Vector Byte Manipulation Instructions 2 | |||
| HasAVX512BITALG bool // Advanced vector extension 512 Bit Algorithms | |||
| HasAVX512BF16 bool // Advanced vector extension 512 BFloat16 Instructions | |||
| HasBMI1 bool // Bit manipulation instruction set 1 | |||
| HasBMI2 bool // Bit manipulation instruction set 2 | |||
| HasERMS bool // Enhanced REP for MOVSB and STOSB | |||
| HasFMA bool // Fused-multiply-add instructions | |||
| HasOSXSAVE bool // OS supports XSAVE/XRESTOR for saving/restoring XMM registers. | |||
| HasPCLMULQDQ bool // PCLMULQDQ instruction - most often used for AES-GCM | |||
| HasPOPCNT bool // Hamming weight instruction POPCNT. | |||
| HasRDRAND bool // RDRAND instruction (on-chip random number generator) | |||
| HasRDSEED bool // RDSEED instruction (on-chip random number generator) | |||
| HasSSE2 bool // Streaming SIMD extension 2 (always available on amd64) | |||
| HasSSE3 bool // Streaming SIMD extension 3 | |||
| HasSSSE3 bool // Supplemental streaming SIMD extension 3 | |||
| HasSSE41 bool // Streaming SIMD extension 4 and 4.1 | |||
| HasSSE42 bool // Streaming SIMD extension 4 and 4.2 | |||
| _ CacheLinePad | |||
| } | |||
| // ARM64 contains the supported CPU features of the | |||
| @@ -169,3 +194,94 @@ var S390X struct { | |||
| HasVXE bool // vector-enhancements facility 1 | |||
| _ CacheLinePad | |||
| } | |||
| func init() { | |||
| archInit() | |||
| initOptions() | |||
| processOptions() | |||
| } | |||
| // options contains the cpu debug options that can be used in GODEBUG. | |||
| // Options are arch dependent and are added by the arch specific initOptions functions. | |||
| // Features that are mandatory for the specific GOARCH should have the Required field set | |||
| // (e.g. SSE2 on amd64). | |||
| var options []option | |||
| // Option names should be lower case. e.g. avx instead of AVX. | |||
| type option struct { | |||
| Name string | |||
| Feature *bool | |||
| Specified bool // whether feature value was specified in GODEBUG | |||
| Enable bool // whether feature should be enabled | |||
| Required bool // whether feature is mandatory and can not be disabled | |||
| } | |||
| func processOptions() { | |||
| env := os.Getenv("GODEBUG") | |||
| field: | |||
| for env != "" { | |||
| field := "" | |||
| i := strings.IndexByte(env, ',') | |||
| if i < 0 { | |||
| field, env = env, "" | |||
| } else { | |||
| field, env = env[:i], env[i+1:] | |||
| } | |||
| if len(field) < 4 || field[:4] != "cpu." { | |||
| continue | |||
| } | |||
| i = strings.IndexByte(field, '=') | |||
| if i < 0 { | |||
| print("GODEBUG sys/cpu: no value specified for \"", field, "\"\n") | |||
| continue | |||
| } | |||
| key, value := field[4:i], field[i+1:] // e.g. "SSE2", "on" | |||
| var enable bool | |||
| switch value { | |||
| case "on": | |||
| enable = true | |||
| case "off": | |||
| enable = false | |||
| default: | |||
| print("GODEBUG sys/cpu: value \"", value, "\" not supported for cpu option \"", key, "\"\n") | |||
| continue field | |||
| } | |||
| if key == "all" { | |||
| for i := range options { | |||
| options[i].Specified = true | |||
| options[i].Enable = enable || options[i].Required | |||
| } | |||
| continue field | |||
| } | |||
| for i := range options { | |||
| if options[i].Name == key { | |||
| options[i].Specified = true | |||
| options[i].Enable = enable | |||
| continue field | |||
| } | |||
| } | |||
| print("GODEBUG sys/cpu: unknown cpu feature \"", key, "\"\n") | |||
| } | |||
| for _, o := range options { | |||
| if !o.Specified { | |||
| continue | |||
| } | |||
| if o.Enable && !*o.Feature { | |||
| print("GODEBUG sys/cpu: can not enable \"", o.Name, "\", missing CPU support\n") | |||
| continue | |||
| } | |||
| if !o.Enable && o.Required { | |||
| print("GODEBUG sys/cpu: can not disable \"", o.Name, "\", required CPU feature\n") | |||
| continue | |||
| } | |||
| *o.Feature = o.Enable | |||
| } | |||
| } | |||
| @@ -2,12 +2,11 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build aix,ppc64 | |||
| //go:build aix | |||
| // +build aix | |||
| package cpu | |||
| const cacheLineSize = 128 | |||
| const ( | |||
| // getsystemcfg constants | |||
| _SC_IMPL = 2 | |||
| @@ -15,7 +14,7 @@ const ( | |||
| _IMPL_POWER9 = 0x20000 | |||
| ) | |||
| func init() { | |||
| func archInit() { | |||
| impl := getsystemcfg(_SC_IMPL) | |||
| if impl&_IMPL_POWER8 != 0 { | |||
| PPC64.IsPOWER8 = true | |||
| @@ -38,3 +38,36 @@ const ( | |||
| hwcap2_SHA2 = 1 << 3 | |||
| hwcap2_CRC32 = 1 << 4 | |||
| ) | |||
| func initOptions() { | |||
| options = []option{ | |||
| {Name: "pmull", Feature: &ARM.HasPMULL}, | |||
| {Name: "sha1", Feature: &ARM.HasSHA1}, | |||
| {Name: "sha2", Feature: &ARM.HasSHA2}, | |||
| {Name: "swp", Feature: &ARM.HasSWP}, | |||
| {Name: "thumb", Feature: &ARM.HasTHUMB}, | |||
| {Name: "thumbee", Feature: &ARM.HasTHUMBEE}, | |||
| {Name: "tls", Feature: &ARM.HasTLS}, | |||
| {Name: "vfp", Feature: &ARM.HasVFP}, | |||
| {Name: "vfpd32", Feature: &ARM.HasVFPD32}, | |||
| {Name: "vfpv3", Feature: &ARM.HasVFPv3}, | |||
| {Name: "vfpv3d16", Feature: &ARM.HasVFPv3D16}, | |||
| {Name: "vfpv4", Feature: &ARM.HasVFPv4}, | |||
| {Name: "half", Feature: &ARM.HasHALF}, | |||
| {Name: "26bit", Feature: &ARM.Has26BIT}, | |||
| {Name: "fastmul", Feature: &ARM.HasFASTMUL}, | |||
| {Name: "fpa", Feature: &ARM.HasFPA}, | |||
| {Name: "edsp", Feature: &ARM.HasEDSP}, | |||
| {Name: "java", Feature: &ARM.HasJAVA}, | |||
| {Name: "iwmmxt", Feature: &ARM.HasIWMMXT}, | |||
| {Name: "crunch", Feature: &ARM.HasCRUNCH}, | |||
| {Name: "neon", Feature: &ARM.HasNEON}, | |||
| {Name: "idivt", Feature: &ARM.HasIDIVT}, | |||
| {Name: "idiva", Feature: &ARM.HasIDIVA}, | |||
| {Name: "lpae", Feature: &ARM.HasLPAE}, | |||
| {Name: "evtstrm", Feature: &ARM.HasEVTSTRM}, | |||
| {Name: "aes", Feature: &ARM.HasAES}, | |||
| {Name: "crc32", Feature: &ARM.HasCRC32}, | |||
| } | |||
| } | |||
| @@ -8,27 +8,65 @@ import "runtime" | |||
| const cacheLineSize = 64 | |||
| func init() { | |||
| func initOptions() { | |||
| options = []option{ | |||
| {Name: "fp", Feature: &ARM64.HasFP}, | |||
| {Name: "asimd", Feature: &ARM64.HasASIMD}, | |||
| {Name: "evstrm", Feature: &ARM64.HasEVTSTRM}, | |||
| {Name: "aes", Feature: &ARM64.HasAES}, | |||
| {Name: "fphp", Feature: &ARM64.HasFPHP}, | |||
| {Name: "jscvt", Feature: &ARM64.HasJSCVT}, | |||
| {Name: "lrcpc", Feature: &ARM64.HasLRCPC}, | |||
| {Name: "pmull", Feature: &ARM64.HasPMULL}, | |||
| {Name: "sha1", Feature: &ARM64.HasSHA1}, | |||
| {Name: "sha2", Feature: &ARM64.HasSHA2}, | |||
| {Name: "sha3", Feature: &ARM64.HasSHA3}, | |||
| {Name: "sha512", Feature: &ARM64.HasSHA512}, | |||
| {Name: "sm3", Feature: &ARM64.HasSM3}, | |||
| {Name: "sm4", Feature: &ARM64.HasSM4}, | |||
| {Name: "sve", Feature: &ARM64.HasSVE}, | |||
| {Name: "crc32", Feature: &ARM64.HasCRC32}, | |||
| {Name: "atomics", Feature: &ARM64.HasATOMICS}, | |||
| {Name: "asimdhp", Feature: &ARM64.HasASIMDHP}, | |||
| {Name: "cpuid", Feature: &ARM64.HasCPUID}, | |||
| {Name: "asimrdm", Feature: &ARM64.HasASIMDRDM}, | |||
| {Name: "fcma", Feature: &ARM64.HasFCMA}, | |||
| {Name: "dcpop", Feature: &ARM64.HasDCPOP}, | |||
| {Name: "asimddp", Feature: &ARM64.HasASIMDDP}, | |||
| {Name: "asimdfhm", Feature: &ARM64.HasASIMDFHM}, | |||
| } | |||
| } | |||
| func archInit() { | |||
| switch runtime.GOOS { | |||
| case "android", "darwin": | |||
| // Android and iOS don't seem to allow reading these registers. | |||
| // Fake the minimal features expected by | |||
| // TestARM64minimalFeatures. | |||
| ARM64.HasASIMD = true | |||
| ARM64.HasFP = true | |||
| case "linux": | |||
| case "freebsd": | |||
| readARM64Registers() | |||
| case "linux", "netbsd": | |||
| doinit() | |||
| default: | |||
| readARM64Registers() | |||
| // Most platforms don't seem to allow reading these registers. | |||
| // | |||
| // OpenBSD: | |||
| // See https://golang.org/issue/31746 | |||
| setMinimalFeatures() | |||
| } | |||
| } | |||
| // setMinimalFeatures fakes the minimal ARM64 features expected by | |||
| // TestARM64minimalFeatures. | |||
| func setMinimalFeatures() { | |||
| ARM64.HasASIMD = true | |||
| ARM64.HasFP = true | |||
| } | |||
| func readARM64Registers() { | |||
| Initialized = true | |||
| // ID_AA64ISAR0_EL1 | |||
| isar0 := getisar0() | |||
| parseARM64SystemRegisters(getisar0(), getisar1(), getpfr0()) | |||
| } | |||
| func parseARM64SystemRegisters(isar0, isar1, pfr0 uint64) { | |||
| // ID_AA64ISAR0_EL1 | |||
| switch extractBits(isar0, 4, 7) { | |||
| case 1: | |||
| ARM64.HasAES = true | |||
| @@ -86,8 +124,6 @@ func readARM64Registers() { | |||
| } | |||
| // ID_AA64ISAR1_EL1 | |||
| isar1 := getisar1() | |||
| switch extractBits(isar1, 0, 3) { | |||
| case 1: | |||
| ARM64.HasDCPOP = true | |||
| @@ -109,8 +145,6 @@ func readARM64Registers() { | |||
| } | |||
| // ID_AA64PFR0_EL1 | |||
| pfr0 := getpfr0() | |||
| switch extractBits(pfr0, 16, 19) { | |||
| case 0: | |||
| ARM64.HasFP = true | |||
| @@ -2,7 +2,8 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !gccgo | |||
| //go:build gc | |||
| // +build gc | |||
| #include "textflag.h" | |||
| @@ -2,7 +2,8 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !gccgo | |||
| //go:build gc | |||
| // +build gc | |||
| package cpu | |||
| @@ -2,7 +2,8 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !gccgo | |||
| //go:build gc | |||
| // +build gc | |||
| package cpu | |||
| @@ -2,8 +2,9 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build (386 || amd64 || amd64p32) && gc | |||
| // +build 386 amd64 amd64p32 | |||
| // +build !gccgo | |||
| // +build gc | |||
| package cpu | |||
| @@ -14,3 +15,7 @@ func cpuid(eaxArg, ecxArg uint32) (eax, ebx, ecx, edx uint32) | |||
| // xgetbv with ecx = 0 is implemented in cpu_x86.s for gc compiler | |||
| // and in cpu_gccgo.c for gccgo. | |||
| func xgetbv() (eax, edx uint32) | |||
| // darwinSupportsAVX512 is implemented in cpu_x86.s for gc compiler | |||
| // and in cpu_gccgo_x86.go for gccgo. | |||
| func darwinSupportsAVX512() bool | |||
| @@ -2,6 +2,7 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build gccgo | |||
| // +build gccgo | |||
| package cpu | |||
| @@ -2,6 +2,7 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build gccgo | |||
| // +build gccgo | |||
| package cpu | |||
| @@ -2,6 +2,7 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build (386 || amd64 || amd64p32) && gccgo | |||
| // +build 386 amd64 amd64p32 | |||
| // +build gccgo | |||
| @@ -24,3 +25,9 @@ func xgetbv() (eax, edx uint32) { | |||
| gccgoXgetbv(&a, &d) | |||
| return a, d | |||
| } | |||
| // gccgo doesn't build on Darwin, per: | |||
| // https://github.com/Homebrew/homebrew-core/blob/HEAD/Formula/gcc.rb#L76 | |||
| func darwinSupportsAVX512() bool { | |||
| return false | |||
| } | |||
| @@ -2,11 +2,12 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build !386 && !amd64 && !amd64p32 && !arm64 | |||
| // +build !386,!amd64,!amd64p32,!arm64 | |||
| package cpu | |||
| func init() { | |||
| func archInit() { | |||
| if err := readHWCAP(); err != nil { | |||
| return | |||
| } | |||
| @@ -2,6 +2,8 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build linux && (mips64 || mips64le) | |||
| // +build linux | |||
| // +build mips64 mips64le | |||
| package cpu | |||
| @@ -2,6 +2,7 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build linux && !arm && !arm64 && !mips64 && !mips64le && !ppc64 && !ppc64le && !s390x | |||
| // +build linux,!arm,!arm64,!mips64,!mips64le,!ppc64,!ppc64le,!s390x | |||
| package cpu | |||
| @@ -2,13 +2,12 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build linux && (ppc64 || ppc64le) | |||
| // +build linux | |||
| // +build ppc64 ppc64le | |||
| package cpu | |||
| const cacheLineSize = 128 | |||
| // HWCAP/HWCAP2 bits. These are exposed by the kernel. | |||
| const ( | |||
| // ISA Level | |||
| @@ -4,8 +4,6 @@ | |||
| package cpu | |||
| const cacheLineSize = 256 | |||
| const ( | |||
| // bit mask values from /usr/include/bits/hwcap.h | |||
| hwcap_ZARCH = 2 | |||
| @@ -19,86 +17,7 @@ const ( | |||
| hwcap_VXE = 8192 | |||
| ) | |||
| // bitIsSet reports whether the bit at index is set. The bit index | |||
| // is in big endian order, so bit index 0 is the leftmost bit. | |||
| func bitIsSet(bits []uint64, index uint) bool { | |||
| return bits[index/64]&((1<<63)>>(index%64)) != 0 | |||
| } | |||
| // function is the code for the named cryptographic function. | |||
| type function uint8 | |||
| const ( | |||
| // KM{,A,C,CTR} function codes | |||
| aes128 function = 18 // AES-128 | |||
| aes192 function = 19 // AES-192 | |||
| aes256 function = 20 // AES-256 | |||
| // K{I,L}MD function codes | |||
| sha1 function = 1 // SHA-1 | |||
| sha256 function = 2 // SHA-256 | |||
| sha512 function = 3 // SHA-512 | |||
| sha3_224 function = 32 // SHA3-224 | |||
| sha3_256 function = 33 // SHA3-256 | |||
| sha3_384 function = 34 // SHA3-384 | |||
| sha3_512 function = 35 // SHA3-512 | |||
| shake128 function = 36 // SHAKE-128 | |||
| shake256 function = 37 // SHAKE-256 | |||
| // KLMD function codes | |||
| ghash function = 65 // GHASH | |||
| ) | |||
| // queryResult contains the result of a Query function | |||
| // call. Bits are numbered in big endian order so the | |||
| // leftmost bit (the MSB) is at index 0. | |||
| type queryResult struct { | |||
| bits [2]uint64 | |||
| } | |||
| // Has reports whether the given functions are present. | |||
| func (q *queryResult) Has(fns ...function) bool { | |||
| if len(fns) == 0 { | |||
| panic("no function codes provided") | |||
| } | |||
| for _, f := range fns { | |||
| if !bitIsSet(q.bits[:], uint(f)) { | |||
| return false | |||
| } | |||
| } | |||
| return true | |||
| } | |||
| // facility is a bit index for the named facility. | |||
| type facility uint8 | |||
| const ( | |||
| // cryptography facilities | |||
| msa4 facility = 77 // message-security-assist extension 4 | |||
| msa8 facility = 146 // message-security-assist extension 8 | |||
| ) | |||
| // facilityList contains the result of an STFLE call. | |||
| // Bits are numbered in big endian order so the | |||
| // leftmost bit (the MSB) is at index 0. | |||
| type facilityList struct { | |||
| bits [4]uint64 | |||
| } | |||
| // Has reports whether the given facilities are present. | |||
| func (s *facilityList) Has(fs ...facility) bool { | |||
| if len(fs) == 0 { | |||
| panic("no facility bits provided") | |||
| } | |||
| for _, f := range fs { | |||
| if !bitIsSet(s.bits[:], uint(f)) { | |||
| return false | |||
| } | |||
| } | |||
| return true | |||
| } | |||
| func doinit() { | |||
| func initS390Xbase() { | |||
| // test HWCAP bit vector | |||
| has := func(featureMask uint) bool { | |||
| return hwCap&featureMask == featureMask | |||
| @@ -118,44 +37,4 @@ func doinit() { | |||
| if S390X.HasVX { | |||
| S390X.HasVXE = has(hwcap_VXE) | |||
| } | |||
| // We need implementations of stfle, km and so on | |||
| // to detect cryptographic features. | |||
| if !haveAsmFunctions() { | |||
| return | |||
| } | |||
| // optional cryptographic functions | |||
| if S390X.HasMSA { | |||
| aes := []function{aes128, aes192, aes256} | |||
| // cipher message | |||
| km, kmc := kmQuery(), kmcQuery() | |||
| S390X.HasAES = km.Has(aes...) | |||
| S390X.HasAESCBC = kmc.Has(aes...) | |||
| if S390X.HasSTFLE { | |||
| facilities := stfle() | |||
| if facilities.Has(msa4) { | |||
| kmctr := kmctrQuery() | |||
| S390X.HasAESCTR = kmctr.Has(aes...) | |||
| } | |||
| if facilities.Has(msa8) { | |||
| kma := kmaQuery() | |||
| S390X.HasAESGCM = kma.Has(aes...) | |||
| } | |||
| } | |||
| // compute message digest | |||
| kimd := kimdQuery() // intermediate (no padding) | |||
| klmd := klmdQuery() // last (padding) | |||
| S390X.HasSHA1 = kimd.Has(sha1) && klmd.Has(sha1) | |||
| S390X.HasSHA256 = kimd.Has(sha256) && klmd.Has(sha256) | |||
| S390X.HasSHA512 = kimd.Has(sha512) && klmd.Has(sha512) | |||
| S390X.HasGHASH = kimd.Has(ghash) // KLMD-GHASH does not exist | |||
| sha3 := []function{ | |||
| sha3_224, sha3_256, sha3_384, sha3_512, | |||
| shake128, shake256, | |||
| } | |||
| S390X.HasSHA3 = kimd.Has(sha3...) && klmd.Has(sha3...) | |||
| } | |||
| } | |||
| @@ -2,8 +2,15 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build mips64 || mips64le | |||
| // +build mips64 mips64le | |||
| package cpu | |||
| const cacheLineSize = 32 | |||
| func initOptions() { | |||
| options = []option{ | |||
| {Name: "msa", Feature: &MIPS64X.HasMSA}, | |||
| } | |||
| } | |||
| @@ -2,8 +2,11 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build mips || mipsle | |||
| // +build mips mipsle | |||
| package cpu | |||
| const cacheLineSize = 32 | |||
| func initOptions() {} | |||
| @@ -0,0 +1,173 @@ | |||
| // Copyright 2020 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| package cpu | |||
| import ( | |||
| "syscall" | |||
| "unsafe" | |||
| ) | |||
| // Minimal copy of functionality from x/sys/unix so the cpu package can call | |||
| // sysctl without depending on x/sys/unix. | |||
| const ( | |||
| _CTL_QUERY = -2 | |||
| _SYSCTL_VERS_1 = 0x1000000 | |||
| ) | |||
| var _zero uintptr | |||
| func sysctl(mib []int32, old *byte, oldlen *uintptr, new *byte, newlen uintptr) (err error) { | |||
| var _p0 unsafe.Pointer | |||
| if len(mib) > 0 { | |||
| _p0 = unsafe.Pointer(&mib[0]) | |||
| } else { | |||
| _p0 = unsafe.Pointer(&_zero) | |||
| } | |||
| _, _, errno := syscall.Syscall6( | |||
| syscall.SYS___SYSCTL, | |||
| uintptr(_p0), | |||
| uintptr(len(mib)), | |||
| uintptr(unsafe.Pointer(old)), | |||
| uintptr(unsafe.Pointer(oldlen)), | |||
| uintptr(unsafe.Pointer(new)), | |||
| uintptr(newlen)) | |||
| if errno != 0 { | |||
| return errno | |||
| } | |||
| return nil | |||
| } | |||
| type sysctlNode struct { | |||
| Flags uint32 | |||
| Num int32 | |||
| Name [32]int8 | |||
| Ver uint32 | |||
| __rsvd uint32 | |||
| Un [16]byte | |||
| _sysctl_size [8]byte | |||
| _sysctl_func [8]byte | |||
| _sysctl_parent [8]byte | |||
| _sysctl_desc [8]byte | |||
| } | |||
| func sysctlNodes(mib []int32) ([]sysctlNode, error) { | |||
| var olen uintptr | |||
| // Get a list of all sysctl nodes below the given MIB by performing | |||
| // a sysctl for the given MIB with CTL_QUERY appended. | |||
| mib = append(mib, _CTL_QUERY) | |||
| qnode := sysctlNode{Flags: _SYSCTL_VERS_1} | |||
| qp := (*byte)(unsafe.Pointer(&qnode)) | |||
| sz := unsafe.Sizeof(qnode) | |||
| if err := sysctl(mib, nil, &olen, qp, sz); err != nil { | |||
| return nil, err | |||
| } | |||
| // Now that we know the size, get the actual nodes. | |||
| nodes := make([]sysctlNode, olen/sz) | |||
| np := (*byte)(unsafe.Pointer(&nodes[0])) | |||
| if err := sysctl(mib, np, &olen, qp, sz); err != nil { | |||
| return nil, err | |||
| } | |||
| return nodes, nil | |||
| } | |||
| func nametomib(name string) ([]int32, error) { | |||
| // Split name into components. | |||
| var parts []string | |||
| last := 0 | |||
| for i := 0; i < len(name); i++ { | |||
| if name[i] == '.' { | |||
| parts = append(parts, name[last:i]) | |||
| last = i + 1 | |||
| } | |||
| } | |||
| parts = append(parts, name[last:]) | |||
| mib := []int32{} | |||
| // Discover the nodes and construct the MIB OID. | |||
| for partno, part := range parts { | |||
| nodes, err := sysctlNodes(mib) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| for _, node := range nodes { | |||
| n := make([]byte, 0) | |||
| for i := range node.Name { | |||
| if node.Name[i] != 0 { | |||
| n = append(n, byte(node.Name[i])) | |||
| } | |||
| } | |||
| if string(n) == part { | |||
| mib = append(mib, int32(node.Num)) | |||
| break | |||
| } | |||
| } | |||
| if len(mib) != partno+1 { | |||
| return nil, err | |||
| } | |||
| } | |||
| return mib, nil | |||
| } | |||
| // aarch64SysctlCPUID is struct aarch64_sysctl_cpu_id from NetBSD's <aarch64/armreg.h> | |||
| type aarch64SysctlCPUID struct { | |||
| midr uint64 /* Main ID Register */ | |||
| revidr uint64 /* Revision ID Register */ | |||
| mpidr uint64 /* Multiprocessor Affinity Register */ | |||
| aa64dfr0 uint64 /* A64 Debug Feature Register 0 */ | |||
| aa64dfr1 uint64 /* A64 Debug Feature Register 1 */ | |||
| aa64isar0 uint64 /* A64 Instruction Set Attribute Register 0 */ | |||
| aa64isar1 uint64 /* A64 Instruction Set Attribute Register 1 */ | |||
| aa64mmfr0 uint64 /* A64 Memory Model Feature Register 0 */ | |||
| aa64mmfr1 uint64 /* A64 Memory Model Feature Register 1 */ | |||
| aa64mmfr2 uint64 /* A64 Memory Model Feature Register 2 */ | |||
| aa64pfr0 uint64 /* A64 Processor Feature Register 0 */ | |||
| aa64pfr1 uint64 /* A64 Processor Feature Register 1 */ | |||
| aa64zfr0 uint64 /* A64 SVE Feature ID Register 0 */ | |||
| mvfr0 uint32 /* Media and VFP Feature Register 0 */ | |||
| mvfr1 uint32 /* Media and VFP Feature Register 1 */ | |||
| mvfr2 uint32 /* Media and VFP Feature Register 2 */ | |||
| pad uint32 | |||
| clidr uint64 /* Cache Level ID Register */ | |||
| ctr uint64 /* Cache Type Register */ | |||
| } | |||
| func sysctlCPUID(name string) (*aarch64SysctlCPUID, error) { | |||
| mib, err := nametomib(name) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| out := aarch64SysctlCPUID{} | |||
| n := unsafe.Sizeof(out) | |||
| _, _, errno := syscall.Syscall6( | |||
| syscall.SYS___SYSCTL, | |||
| uintptr(unsafe.Pointer(&mib[0])), | |||
| uintptr(len(mib)), | |||
| uintptr(unsafe.Pointer(&out)), | |||
| uintptr(unsafe.Pointer(&n)), | |||
| uintptr(0), | |||
| uintptr(0)) | |||
| if errno != 0 { | |||
| return nil, errno | |||
| } | |||
| return &out, nil | |||
| } | |||
| func doinit() { | |||
| cpuid, err := sysctlCPUID("machdep.cpu0.cpu_id") | |||
| if err != nil { | |||
| setMinimalFeatures() | |||
| return | |||
| } | |||
| parseARM64SystemRegisters(cpuid.aa64isar0, cpuid.aa64isar1, cpuid.aa64pfr0) | |||
| Initialized = true | |||
| } | |||
| @@ -0,0 +1,10 @@ | |||
| // Copyright 2020 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build !linux && arm | |||
| // +build !linux,arm | |||
| package cpu | |||
| func archInit() {} | |||
| @@ -2,7 +2,8 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !linux,arm64 | |||
| //go:build !linux && !netbsd && arm64 | |||
| // +build !linux,!netbsd,arm64 | |||
| package cpu | |||
| @@ -0,0 +1,13 @@ | |||
| // Copyright 2020 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build !linux && (mips64 || mips64le) | |||
| // +build !linux | |||
| // +build mips64 mips64le | |||
| package cpu | |||
| func archInit() { | |||
| Initialized = true | |||
| } | |||
| @@ -0,0 +1,17 @@ | |||
| // Copyright 2020 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build ppc64 || ppc64le | |||
| // +build ppc64 ppc64le | |||
| package cpu | |||
| const cacheLineSize = 128 | |||
| func initOptions() { | |||
| options = []option{ | |||
| {Name: "darn", Feature: &PPC64.HasDARN}, | |||
| {Name: "scv", Feature: &PPC64.HasSCV}, | |||
| } | |||
| } | |||
| @@ -2,8 +2,11 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build riscv64 | |||
| // +build riscv64 | |||
| package cpu | |||
| const cacheLineSize = 32 | |||
| func initOptions() {} | |||
| @@ -0,0 +1,172 @@ | |||
| // Copyright 2020 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| package cpu | |||
| const cacheLineSize = 256 | |||
| func initOptions() { | |||
| options = []option{ | |||
| {Name: "zarch", Feature: &S390X.HasZARCH, Required: true}, | |||
| {Name: "stfle", Feature: &S390X.HasSTFLE, Required: true}, | |||
| {Name: "ldisp", Feature: &S390X.HasLDISP, Required: true}, | |||
| {Name: "eimm", Feature: &S390X.HasEIMM, Required: true}, | |||
| {Name: "dfp", Feature: &S390X.HasDFP}, | |||
| {Name: "etf3eh", Feature: &S390X.HasETF3EH}, | |||
| {Name: "msa", Feature: &S390X.HasMSA}, | |||
| {Name: "aes", Feature: &S390X.HasAES}, | |||
| {Name: "aescbc", Feature: &S390X.HasAESCBC}, | |||
| {Name: "aesctr", Feature: &S390X.HasAESCTR}, | |||
| {Name: "aesgcm", Feature: &S390X.HasAESGCM}, | |||
| {Name: "ghash", Feature: &S390X.HasGHASH}, | |||
| {Name: "sha1", Feature: &S390X.HasSHA1}, | |||
| {Name: "sha256", Feature: &S390X.HasSHA256}, | |||
| {Name: "sha3", Feature: &S390X.HasSHA3}, | |||
| {Name: "sha512", Feature: &S390X.HasSHA512}, | |||
| {Name: "vx", Feature: &S390X.HasVX}, | |||
| {Name: "vxe", Feature: &S390X.HasVXE}, | |||
| } | |||
| } | |||
| // bitIsSet reports whether the bit at index is set. The bit index | |||
| // is in big endian order, so bit index 0 is the leftmost bit. | |||
| func bitIsSet(bits []uint64, index uint) bool { | |||
| return bits[index/64]&((1<<63)>>(index%64)) != 0 | |||
| } | |||
| // facility is a bit index for the named facility. | |||
| type facility uint8 | |||
| const ( | |||
| // mandatory facilities | |||
| zarch facility = 1 // z architecture mode is active | |||
| stflef facility = 7 // store-facility-list-extended | |||
| ldisp facility = 18 // long-displacement | |||
| eimm facility = 21 // extended-immediate | |||
| // miscellaneous facilities | |||
| dfp facility = 42 // decimal-floating-point | |||
| etf3eh facility = 30 // extended-translation 3 enhancement | |||
| // cryptography facilities | |||
| msa facility = 17 // message-security-assist | |||
| msa3 facility = 76 // message-security-assist extension 3 | |||
| msa4 facility = 77 // message-security-assist extension 4 | |||
| msa5 facility = 57 // message-security-assist extension 5 | |||
| msa8 facility = 146 // message-security-assist extension 8 | |||
| msa9 facility = 155 // message-security-assist extension 9 | |||
| // vector facilities | |||
| vx facility = 129 // vector facility | |||
| vxe facility = 135 // vector-enhancements 1 | |||
| vxe2 facility = 148 // vector-enhancements 2 | |||
| ) | |||
| // facilityList contains the result of an STFLE call. | |||
| // Bits are numbered in big endian order so the | |||
| // leftmost bit (the MSB) is at index 0. | |||
| type facilityList struct { | |||
| bits [4]uint64 | |||
| } | |||
| // Has reports whether the given facilities are present. | |||
| func (s *facilityList) Has(fs ...facility) bool { | |||
| if len(fs) == 0 { | |||
| panic("no facility bits provided") | |||
| } | |||
| for _, f := range fs { | |||
| if !bitIsSet(s.bits[:], uint(f)) { | |||
| return false | |||
| } | |||
| } | |||
| return true | |||
| } | |||
| // function is the code for the named cryptographic function. | |||
| type function uint8 | |||
| const ( | |||
| // KM{,A,C,CTR} function codes | |||
| aes128 function = 18 // AES-128 | |||
| aes192 function = 19 // AES-192 | |||
| aes256 function = 20 // AES-256 | |||
| // K{I,L}MD function codes | |||
| sha1 function = 1 // SHA-1 | |||
| sha256 function = 2 // SHA-256 | |||
| sha512 function = 3 // SHA-512 | |||
| sha3_224 function = 32 // SHA3-224 | |||
| sha3_256 function = 33 // SHA3-256 | |||
| sha3_384 function = 34 // SHA3-384 | |||
| sha3_512 function = 35 // SHA3-512 | |||
| shake128 function = 36 // SHAKE-128 | |||
| shake256 function = 37 // SHAKE-256 | |||
| // KLMD function codes | |||
| ghash function = 65 // GHASH | |||
| ) | |||
| // queryResult contains the result of a Query function | |||
| // call. Bits are numbered in big endian order so the | |||
| // leftmost bit (the MSB) is at index 0. | |||
| type queryResult struct { | |||
| bits [2]uint64 | |||
| } | |||
| // Has reports whether the given functions are present. | |||
| func (q *queryResult) Has(fns ...function) bool { | |||
| if len(fns) == 0 { | |||
| panic("no function codes provided") | |||
| } | |||
| for _, f := range fns { | |||
| if !bitIsSet(q.bits[:], uint(f)) { | |||
| return false | |||
| } | |||
| } | |||
| return true | |||
| } | |||
| func doinit() { | |||
| initS390Xbase() | |||
| // We need implementations of stfle, km and so on | |||
| // to detect cryptographic features. | |||
| if !haveAsmFunctions() { | |||
| return | |||
| } | |||
| // optional cryptographic functions | |||
| if S390X.HasMSA { | |||
| aes := []function{aes128, aes192, aes256} | |||
| // cipher message | |||
| km, kmc := kmQuery(), kmcQuery() | |||
| S390X.HasAES = km.Has(aes...) | |||
| S390X.HasAESCBC = kmc.Has(aes...) | |||
| if S390X.HasSTFLE { | |||
| facilities := stfle() | |||
| if facilities.Has(msa4) { | |||
| kmctr := kmctrQuery() | |||
| S390X.HasAESCTR = kmctr.Has(aes...) | |||
| } | |||
| if facilities.Has(msa8) { | |||
| kma := kmaQuery() | |||
| S390X.HasAESGCM = kma.Has(aes...) | |||
| } | |||
| } | |||
| // compute message digest | |||
| kimd := kimdQuery() // intermediate (no padding) | |||
| klmd := klmdQuery() // last (padding) | |||
| S390X.HasSHA1 = kimd.Has(sha1) && klmd.Has(sha1) | |||
| S390X.HasSHA256 = kimd.Has(sha256) && klmd.Has(sha256) | |||
| S390X.HasSHA512 = kimd.Has(sha512) && klmd.Has(sha512) | |||
| S390X.HasGHASH = kimd.Has(ghash) // KLMD-GHASH does not exist | |||
| sha3 := []function{ | |||
| sha3_224, sha3_256, sha3_384, sha3_512, | |||
| shake128, shake256, | |||
| } | |||
| S390X.HasSHA3 = kimd.Has(sha3...) && klmd.Has(sha3...) | |||
| } | |||
| } | |||
| @@ -2,7 +2,8 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !gccgo | |||
| //go:build gc | |||
| // +build gc | |||
| #include "textflag.h" | |||
| @@ -2,6 +2,7 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build wasm | |||
| // +build wasm | |||
| package cpu | |||
| @@ -11,3 +12,7 @@ package cpu | |||
| // rules are good enough. | |||
| const cacheLineSize = 0 | |||
| func initOptions() {} | |||
| func archInit() {} | |||
| @@ -2,13 +2,62 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build 386 || amd64 || amd64p32 | |||
| // +build 386 amd64 amd64p32 | |||
| package cpu | |||
| import "runtime" | |||
| const cacheLineSize = 64 | |||
| func init() { | |||
| func initOptions() { | |||
| options = []option{ | |||
| {Name: "adx", Feature: &X86.HasADX}, | |||
| {Name: "aes", Feature: &X86.HasAES}, | |||
| {Name: "avx", Feature: &X86.HasAVX}, | |||
| {Name: "avx2", Feature: &X86.HasAVX2}, | |||
| {Name: "avx512", Feature: &X86.HasAVX512}, | |||
| {Name: "avx512f", Feature: &X86.HasAVX512F}, | |||
| {Name: "avx512cd", Feature: &X86.HasAVX512CD}, | |||
| {Name: "avx512er", Feature: &X86.HasAVX512ER}, | |||
| {Name: "avx512pf", Feature: &X86.HasAVX512PF}, | |||
| {Name: "avx512vl", Feature: &X86.HasAVX512VL}, | |||
| {Name: "avx512bw", Feature: &X86.HasAVX512BW}, | |||
| {Name: "avx512dq", Feature: &X86.HasAVX512DQ}, | |||
| {Name: "avx512ifma", Feature: &X86.HasAVX512IFMA}, | |||
| {Name: "avx512vbmi", Feature: &X86.HasAVX512VBMI}, | |||
| {Name: "avx512vnniw", Feature: &X86.HasAVX5124VNNIW}, | |||
| {Name: "avx5124fmaps", Feature: &X86.HasAVX5124FMAPS}, | |||
| {Name: "avx512vpopcntdq", Feature: &X86.HasAVX512VPOPCNTDQ}, | |||
| {Name: "avx512vpclmulqdq", Feature: &X86.HasAVX512VPCLMULQDQ}, | |||
| {Name: "avx512vnni", Feature: &X86.HasAVX512VNNI}, | |||
| {Name: "avx512gfni", Feature: &X86.HasAVX512GFNI}, | |||
| {Name: "avx512vaes", Feature: &X86.HasAVX512VAES}, | |||
| {Name: "avx512vbmi2", Feature: &X86.HasAVX512VBMI2}, | |||
| {Name: "avx512bitalg", Feature: &X86.HasAVX512BITALG}, | |||
| {Name: "avx512bf16", Feature: &X86.HasAVX512BF16}, | |||
| {Name: "bmi1", Feature: &X86.HasBMI1}, | |||
| {Name: "bmi2", Feature: &X86.HasBMI2}, | |||
| {Name: "erms", Feature: &X86.HasERMS}, | |||
| {Name: "fma", Feature: &X86.HasFMA}, | |||
| {Name: "osxsave", Feature: &X86.HasOSXSAVE}, | |||
| {Name: "pclmulqdq", Feature: &X86.HasPCLMULQDQ}, | |||
| {Name: "popcnt", Feature: &X86.HasPOPCNT}, | |||
| {Name: "rdrand", Feature: &X86.HasRDRAND}, | |||
| {Name: "rdseed", Feature: &X86.HasRDSEED}, | |||
| {Name: "sse3", Feature: &X86.HasSSE3}, | |||
| {Name: "sse41", Feature: &X86.HasSSE41}, | |||
| {Name: "sse42", Feature: &X86.HasSSE42}, | |||
| {Name: "ssse3", Feature: &X86.HasSSSE3}, | |||
| // These capabilities should always be enabled on amd64: | |||
| {Name: "sse2", Feature: &X86.HasSSE2, Required: runtime.GOARCH == "amd64"}, | |||
| } | |||
| } | |||
| func archInit() { | |||
| Initialized = true | |||
| maxID, _, _, _ := cpuid(0, 0) | |||
| @@ -31,12 +80,21 @@ func init() { | |||
| X86.HasOSXSAVE = isSet(27, ecx1) | |||
| X86.HasRDRAND = isSet(30, ecx1) | |||
| osSupportsAVX := false | |||
| var osSupportsAVX, osSupportsAVX512 bool | |||
| // For XGETBV, OSXSAVE bit is required and sufficient. | |||
| if X86.HasOSXSAVE { | |||
| eax, _ := xgetbv() | |||
| // Check if XMM and YMM registers have OS support. | |||
| osSupportsAVX = isSet(1, eax) && isSet(2, eax) | |||
| if runtime.GOOS == "darwin" { | |||
| // Check darwin commpage for AVX512 support. Necessary because: | |||
| // https://github.com/apple/darwin-xnu/blob/0a798f6738bc1db01281fc08ae024145e84df927/osfmk/i386/fpu.c#L175-L201 | |||
| osSupportsAVX512 = osSupportsAVX && darwinSupportsAVX512() | |||
| } else { | |||
| // Check if OPMASK and ZMM registers have OS support. | |||
| osSupportsAVX512 = osSupportsAVX && isSet(5, eax) && isSet(6, eax) && isSet(7, eax) | |||
| } | |||
| } | |||
| X86.HasAVX = isSet(28, ecx1) && osSupportsAVX | |||
| @@ -45,13 +103,38 @@ func init() { | |||
| return | |||
| } | |||
| _, ebx7, _, _ := cpuid(7, 0) | |||
| _, ebx7, ecx7, edx7 := cpuid(7, 0) | |||
| X86.HasBMI1 = isSet(3, ebx7) | |||
| X86.HasAVX2 = isSet(5, ebx7) && osSupportsAVX | |||
| X86.HasBMI2 = isSet(8, ebx7) | |||
| X86.HasERMS = isSet(9, ebx7) | |||
| X86.HasRDSEED = isSet(18, ebx7) | |||
| X86.HasADX = isSet(19, ebx7) | |||
| X86.HasAVX512 = isSet(16, ebx7) && osSupportsAVX512 // Because avx-512 foundation is the core required extension | |||
| if X86.HasAVX512 { | |||
| X86.HasAVX512F = true | |||
| X86.HasAVX512CD = isSet(28, ebx7) | |||
| X86.HasAVX512ER = isSet(27, ebx7) | |||
| X86.HasAVX512PF = isSet(26, ebx7) | |||
| X86.HasAVX512VL = isSet(31, ebx7) | |||
| X86.HasAVX512BW = isSet(30, ebx7) | |||
| X86.HasAVX512DQ = isSet(17, ebx7) | |||
| X86.HasAVX512IFMA = isSet(21, ebx7) | |||
| X86.HasAVX512VBMI = isSet(1, ecx7) | |||
| X86.HasAVX5124VNNIW = isSet(2, edx7) | |||
| X86.HasAVX5124FMAPS = isSet(3, edx7) | |||
| X86.HasAVX512VPOPCNTDQ = isSet(14, ecx7) | |||
| X86.HasAVX512VPCLMULQDQ = isSet(10, ecx7) | |||
| X86.HasAVX512VNNI = isSet(11, ecx7) | |||
| X86.HasAVX512GFNI = isSet(8, ecx7) | |||
| X86.HasAVX512VAES = isSet(9, ecx7) | |||
| X86.HasAVX512VBMI2 = isSet(6, ecx7) | |||
| X86.HasAVX512BITALG = isSet(12, ecx7) | |||
| eax71, _, _, _ := cpuid(7, 1) | |||
| X86.HasAVX512BF16 = isSet(5, eax71) | |||
| } | |||
| } | |||
| func isSet(bitpos uint, value uint32) bool { | |||
| @@ -2,8 +2,9 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build (386 || amd64 || amd64p32) && gc | |||
| // +build 386 amd64 amd64p32 | |||
| // +build !gccgo | |||
| // +build gc | |||
| #include "textflag.h" | |||
| @@ -25,3 +26,27 @@ TEXT ·xgetbv(SB),NOSPLIT,$0-8 | |||
| MOVL AX, eax+0(FP) | |||
| MOVL DX, edx+4(FP) | |||
| RET | |||
| // func darwinSupportsAVX512() bool | |||
| TEXT ·darwinSupportsAVX512(SB), NOSPLIT, $0-1 | |||
| MOVB $0, ret+0(FP) // default to false | |||
| #ifdef GOOS_darwin // return if not darwin | |||
| #ifdef GOARCH_amd64 // return if not amd64 | |||
| // These values from: | |||
| // https://github.com/apple/darwin-xnu/blob/xnu-4570.1.46/osfmk/i386/cpu_capabilities.h | |||
| #define commpage64_base_address 0x00007fffffe00000 | |||
| #define commpage64_cpu_capabilities64 (commpage64_base_address+0x010) | |||
| #define commpage64_version (commpage64_base_address+0x01E) | |||
| #define hasAVX512F 0x0000004000000000 | |||
| MOVQ $commpage64_version, BX | |||
| CMPW (BX), $13 // cpu_capabilities64 undefined in versions < 13 | |||
| JL no_avx512 | |||
| MOVQ $commpage64_cpu_capabilities64, BX | |||
| MOVQ $hasAVX512F, CX | |||
| TESTQ (BX), CX | |||
| JZ no_avx512 | |||
| MOVB $1, ret+0(FP) | |||
| no_avx512: | |||
| #endif | |||
| #endif | |||
| RET | |||
| @@ -0,0 +1,10 @@ | |||
| // Copyright 2020 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| package cpu | |||
| func archInit() { | |||
| doinit() | |||
| Initialized = true | |||
| } | |||
| @@ -0,0 +1,25 @@ | |||
| // Copyright 2020 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| package cpu | |||
| func initS390Xbase() { | |||
| // get the facilities list | |||
| facilities := stfle() | |||
| // mandatory | |||
| S390X.HasZARCH = facilities.Has(zarch) | |||
| S390X.HasSTFLE = facilities.Has(stflef) | |||
| S390X.HasLDISP = facilities.Has(ldisp) | |||
| S390X.HasEIMM = facilities.Has(eimm) | |||
| // optional | |||
| S390X.HasETF3EH = facilities.Has(etf3eh) | |||
| S390X.HasDFP = facilities.Has(dfp) | |||
| S390X.HasMSA = facilities.Has(msa) | |||
| S390X.HasVX = facilities.Has(vx) | |||
| if S390X.HasVX { | |||
| S390X.HasVXE = facilities.Has(vxe) | |||
| } | |||
| } | |||
| @@ -0,0 +1,27 @@ | |||
| // Copyright 2020 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // Recreate a getsystemcfg syscall handler instead of | |||
| // using the one provided by x/sys/unix to avoid having | |||
| // the dependency between them. (See golang.org/issue/32102) | |||
| // Morever, this file will be used during the building of | |||
| // gccgo's libgo and thus must not used a CGo method. | |||
| //go:build aix && gccgo | |||
| // +build aix,gccgo | |||
| package cpu | |||
| import ( | |||
| "syscall" | |||
| ) | |||
| //extern getsystemcfg | |||
| func gccgoGetsystemcfg(label uint32) (r uint64) | |||
| func callgetsystemcfg(label int) (r1 uintptr, e1 syscall.Errno) { | |||
| r1 = uintptr(gccgoGetsystemcfg(uint32(label))) | |||
| e1 = syscall.GetErrno() | |||
| return | |||
| } | |||
| @@ -6,8 +6,8 @@ | |||
| // system call on AIX without depending on x/sys/unix. | |||
| // (See golang.org/issue/32102) | |||
| // +build aix,ppc64 | |||
| // +build !gccgo | |||
| //go:build aix && ppc64 && gc | |||
| // +build aix,ppc64,gc | |||
| package cpu | |||
| @@ -0,0 +1,102 @@ | |||
| // Copyright 2020 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // Package execabs is a drop-in replacement for os/exec | |||
| // that requires PATH lookups to find absolute paths. | |||
| // That is, execabs.Command("cmd") runs the same PATH lookup | |||
| // as exec.Command("cmd"), but if the result is a path | |||
| // which is relative, the Run and Start methods will report | |||
| // an error instead of running the executable. | |||
| // | |||
| // See https://blog.golang.org/path-security for more information | |||
| // about when it may be necessary or appropriate to use this package. | |||
| package execabs | |||
| import ( | |||
| "context" | |||
| "fmt" | |||
| "os/exec" | |||
| "path/filepath" | |||
| "reflect" | |||
| "unsafe" | |||
| ) | |||
| // ErrNotFound is the error resulting if a path search failed to find an executable file. | |||
| // It is an alias for exec.ErrNotFound. | |||
| var ErrNotFound = exec.ErrNotFound | |||
| // Cmd represents an external command being prepared or run. | |||
| // It is an alias for exec.Cmd. | |||
| type Cmd = exec.Cmd | |||
| // Error is returned by LookPath when it fails to classify a file as an executable. | |||
| // It is an alias for exec.Error. | |||
| type Error = exec.Error | |||
| // An ExitError reports an unsuccessful exit by a command. | |||
| // It is an alias for exec.ExitError. | |||
| type ExitError = exec.ExitError | |||
| func relError(file, path string) error { | |||
| return fmt.Errorf("%s resolves to executable in current directory (.%c%s)", file, filepath.Separator, path) | |||
| } | |||
| // LookPath searches for an executable named file in the directories | |||
| // named by the PATH environment variable. If file contains a slash, | |||
| // it is tried directly and the PATH is not consulted. The result will be | |||
| // an absolute path. | |||
| // | |||
| // LookPath differs from exec.LookPath in its handling of PATH lookups, | |||
| // which are used for file names without slashes. If exec.LookPath's | |||
| // PATH lookup would have returned an executable from the current directory, | |||
| // LookPath instead returns an error. | |||
| func LookPath(file string) (string, error) { | |||
| path, err := exec.LookPath(file) | |||
| if err != nil { | |||
| return "", err | |||
| } | |||
| if filepath.Base(file) == file && !filepath.IsAbs(path) { | |||
| return "", relError(file, path) | |||
| } | |||
| return path, nil | |||
| } | |||
| func fixCmd(name string, cmd *exec.Cmd) { | |||
| if filepath.Base(name) == name && !filepath.IsAbs(cmd.Path) { | |||
| // exec.Command was called with a bare binary name and | |||
| // exec.LookPath returned a path which is not absolute. | |||
| // Set cmd.lookPathErr and clear cmd.Path so that it | |||
| // cannot be run. | |||
| lookPathErr := (*error)(unsafe.Pointer(reflect.ValueOf(cmd).Elem().FieldByName("lookPathErr").Addr().Pointer())) | |||
| if *lookPathErr == nil { | |||
| *lookPathErr = relError(name, cmd.Path) | |||
| } | |||
| cmd.Path = "" | |||
| } | |||
| } | |||
| // CommandContext is like Command but includes a context. | |||
| // | |||
| // The provided context is used to kill the process (by calling os.Process.Kill) | |||
| // if the context becomes done before the command completes on its own. | |||
| func CommandContext(ctx context.Context, name string, arg ...string) *exec.Cmd { | |||
| cmd := exec.CommandContext(ctx, name, arg...) | |||
| fixCmd(name, cmd) | |||
| return cmd | |||
| } | |||
| // Command returns the Cmd struct to execute the named program with the given arguments. | |||
| // See exec.Command for most details. | |||
| // | |||
| // Command differs from exec.Command in its handling of PATH lookups, | |||
| // which are used when the program name contains no slashes. | |||
| // If exec.Command would have returned an exec.Cmd configured to run an | |||
| // executable from the current directory, Command instead | |||
| // returns an exec.Cmd that will return an error from Start or Run. | |||
| func Command(name string, arg ...string) *exec.Cmd { | |||
| cmd := exec.Command(name, arg...) | |||
| fixCmd(name, cmd) | |||
| return cmd | |||
| } | |||
| @@ -2,7 +2,8 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris | |||
| //go:build (aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos) && go1.9 | |||
| // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos | |||
| // +build go1.9 | |||
| package unix | |||
| @@ -2,7 +2,8 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !gccgo | |||
| //go:build gc | |||
| // +build gc | |||
| #include "textflag.h" | |||
| @@ -1,14 +1,14 @@ | |||
| // Copyright 2009 The Go Authors. All rights reserved. | |||
| // Copyright 2021 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !gccgo | |||
| //go:build (darwin || freebsd || netbsd || openbsd) && gc | |||
| // +build darwin freebsd netbsd openbsd | |||
| // +build gc | |||
| #include "textflag.h" | |||
| // | |||
| // System call support for 386, NetBSD | |||
| // | |||
| // System call support for 386 BSD | |||
| // Just jump to package syscall's implementation for all these functions. | |||
| // The runtime may know about them. | |||
| @@ -22,7 +22,7 @@ TEXT ·Syscall6(SB),NOSPLIT,$0-40 | |||
| TEXT ·Syscall9(SB),NOSPLIT,$0-52 | |||
| JMP syscall·Syscall9(SB) | |||
| TEXT ·RawSyscall(SB),NOSPLIT,$0-28 | |||
| TEXT ·RawSyscall(SB),NOSPLIT,$0-28 | |||
| JMP syscall·RawSyscall(SB) | |||
| TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 | |||
| @@ -1,14 +1,14 @@ | |||
| // Copyright 2009 The Go Authors. All rights reserved. | |||
| // Copyright 2021 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !gccgo | |||
| //go:build (darwin || dragonfly || freebsd || netbsd || openbsd) && gc | |||
| // +build darwin dragonfly freebsd netbsd openbsd | |||
| // +build gc | |||
| #include "textflag.h" | |||
| // | |||
| // System call support for AMD64, OpenBSD | |||
| // | |||
| // System call support for AMD64 BSD | |||
| // Just jump to package syscall's implementation for all these functions. | |||
| // The runtime may know about them. | |||
| @@ -1,15 +1,14 @@ | |||
| // Copyright 2015 The Go Authors. All rights reserved. | |||
| // Copyright 2021 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !gccgo | |||
| // +build arm,darwin | |||
| //go:build (darwin || freebsd || netbsd || openbsd) && gc | |||
| // +build darwin freebsd netbsd openbsd | |||
| // +build gc | |||
| #include "textflag.h" | |||
| // | |||
| // System call support for ARM, Darwin | |||
| // | |||
| // System call support for ARM BSD | |||
| // Just jump to package syscall's implementation for all these functions. | |||
| // The runtime may know about them. | |||
| @@ -1,14 +1,14 @@ | |||
| // Copyright 2009 The Go Authors. All rights reserved. | |||
| // Copyright 2021 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !gccgo | |||
| //go:build (darwin || freebsd || netbsd || openbsd) && gc | |||
| // +build darwin freebsd netbsd openbsd | |||
| // +build gc | |||
| #include "textflag.h" | |||
| // | |||
| // System call support for AMD64, NetBSD | |||
| // | |||
| // System call support for ARM64 BSD | |||
| // Just jump to package syscall's implementation for all these functions. | |||
| // The runtime may know about them. | |||
| @@ -1,29 +0,0 @@ | |||
| // Copyright 2009 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !gccgo | |||
| #include "textflag.h" | |||
| // | |||
| // System call support for 386, Darwin | |||
| // | |||
| // Just jump to package syscall's implementation for all these functions. | |||
| // The runtime may know about them. | |||
| TEXT ·Syscall(SB),NOSPLIT,$0-28 | |||
| JMP syscall·Syscall(SB) | |||
| TEXT ·Syscall6(SB),NOSPLIT,$0-40 | |||
| JMP syscall·Syscall6(SB) | |||
| TEXT ·Syscall9(SB),NOSPLIT,$0-52 | |||
| JMP syscall·Syscall9(SB) | |||
| TEXT ·RawSyscall(SB),NOSPLIT,$0-28 | |||
| JMP syscall·RawSyscall(SB) | |||
| TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 | |||
| JMP syscall·RawSyscall6(SB) | |||
| @@ -1,29 +0,0 @@ | |||
| // Copyright 2009 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !gccgo | |||
| #include "textflag.h" | |||
| // | |||
| // System call support for AMD64, Darwin | |||
| // | |||
| // Just jump to package syscall's implementation for all these functions. | |||
| // The runtime may know about them. | |||
| TEXT ·Syscall(SB),NOSPLIT,$0-56 | |||
| JMP syscall·Syscall(SB) | |||
| TEXT ·Syscall6(SB),NOSPLIT,$0-80 | |||
| JMP syscall·Syscall6(SB) | |||
| TEXT ·Syscall9(SB),NOSPLIT,$0-104 | |||
| JMP syscall·Syscall9(SB) | |||
| TEXT ·RawSyscall(SB),NOSPLIT,$0-56 | |||
| JMP syscall·RawSyscall(SB) | |||
| TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 | |||
| JMP syscall·RawSyscall6(SB) | |||
| @@ -1,30 +0,0 @@ | |||
| // Copyright 2015 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !gccgo | |||
| // +build arm64,darwin | |||
| #include "textflag.h" | |||
| // | |||
| // System call support for AMD64, Darwin | |||
| // | |||
| // Just jump to package syscall's implementation for all these functions. | |||
| // The runtime may know about them. | |||
| TEXT ·Syscall(SB),NOSPLIT,$0-56 | |||
| B syscall·Syscall(SB) | |||
| TEXT ·Syscall6(SB),NOSPLIT,$0-80 | |||
| B syscall·Syscall6(SB) | |||
| TEXT ·Syscall9(SB),NOSPLIT,$0-104 | |||
| B syscall·Syscall9(SB) | |||
| TEXT ·RawSyscall(SB),NOSPLIT,$0-56 | |||
| B syscall·RawSyscall(SB) | |||
| TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 | |||
| B syscall·RawSyscall6(SB) | |||
| @@ -1,29 +0,0 @@ | |||
| // Copyright 2009 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !gccgo | |||
| #include "textflag.h" | |||
| // | |||
| // System call support for AMD64, DragonFly | |||
| // | |||
| // Just jump to package syscall's implementation for all these functions. | |||
| // The runtime may know about them. | |||
| TEXT ·Syscall(SB),NOSPLIT,$0-56 | |||
| JMP syscall·Syscall(SB) | |||
| TEXT ·Syscall6(SB),NOSPLIT,$0-80 | |||
| JMP syscall·Syscall6(SB) | |||
| TEXT ·Syscall9(SB),NOSPLIT,$0-104 | |||
| JMP syscall·Syscall9(SB) | |||
| TEXT ·RawSyscall(SB),NOSPLIT,$0-56 | |||
| JMP syscall·RawSyscall(SB) | |||
| TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 | |||
| JMP syscall·RawSyscall6(SB) | |||
| @@ -1,29 +0,0 @@ | |||
| // Copyright 2009 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !gccgo | |||
| #include "textflag.h" | |||
| // | |||
| // System call support for 386, FreeBSD | |||
| // | |||
| // Just jump to package syscall's implementation for all these functions. | |||
| // The runtime may know about them. | |||
| TEXT ·Syscall(SB),NOSPLIT,$0-28 | |||
| JMP syscall·Syscall(SB) | |||
| TEXT ·Syscall6(SB),NOSPLIT,$0-40 | |||
| JMP syscall·Syscall6(SB) | |||
| TEXT ·Syscall9(SB),NOSPLIT,$0-52 | |||
| JMP syscall·Syscall9(SB) | |||
| TEXT ·RawSyscall(SB),NOSPLIT,$0-28 | |||
| JMP syscall·RawSyscall(SB) | |||
| TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 | |||
| JMP syscall·RawSyscall6(SB) | |||
| @@ -1,29 +0,0 @@ | |||
| // Copyright 2009 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !gccgo | |||
| #include "textflag.h" | |||
| // | |||
| // System call support for AMD64, FreeBSD | |||
| // | |||
| // Just jump to package syscall's implementation for all these functions. | |||
| // The runtime may know about them. | |||
| TEXT ·Syscall(SB),NOSPLIT,$0-56 | |||
| JMP syscall·Syscall(SB) | |||
| TEXT ·Syscall6(SB),NOSPLIT,$0-80 | |||
| JMP syscall·Syscall6(SB) | |||
| TEXT ·Syscall9(SB),NOSPLIT,$0-104 | |||
| JMP syscall·Syscall9(SB) | |||
| TEXT ·RawSyscall(SB),NOSPLIT,$0-56 | |||
| JMP syscall·RawSyscall(SB) | |||
| TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 | |||
| JMP syscall·RawSyscall6(SB) | |||
| @@ -1,29 +0,0 @@ | |||
| // Copyright 2012 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !gccgo | |||
| #include "textflag.h" | |||
| // | |||
| // System call support for ARM, FreeBSD | |||
| // | |||
| // Just jump to package syscall's implementation for all these functions. | |||
| // The runtime may know about them. | |||
| TEXT ·Syscall(SB),NOSPLIT,$0-28 | |||
| B syscall·Syscall(SB) | |||
| TEXT ·Syscall6(SB),NOSPLIT,$0-40 | |||
| B syscall·Syscall6(SB) | |||
| TEXT ·Syscall9(SB),NOSPLIT,$0-52 | |||
| B syscall·Syscall9(SB) | |||
| TEXT ·RawSyscall(SB),NOSPLIT,$0-28 | |||
| B syscall·RawSyscall(SB) | |||
| TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 | |||
| B syscall·RawSyscall6(SB) | |||
| @@ -1,29 +0,0 @@ | |||
| // Copyright 2018 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !gccgo | |||
| #include "textflag.h" | |||
| // | |||
| // System call support for ARM64, FreeBSD | |||
| // | |||
| // Just jump to package syscall's implementation for all these functions. | |||
| // The runtime may know about them. | |||
| TEXT ·Syscall(SB),NOSPLIT,$0-56 | |||
| JMP syscall·Syscall(SB) | |||
| TEXT ·Syscall6(SB),NOSPLIT,$0-80 | |||
| JMP syscall·Syscall6(SB) | |||
| TEXT ·Syscall9(SB),NOSPLIT,$0-104 | |||
| JMP syscall·Syscall9(SB) | |||
| TEXT ·RawSyscall(SB),NOSPLIT,$0-56 | |||
| JMP syscall·RawSyscall(SB) | |||
| TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 | |||
| JMP syscall·RawSyscall6(SB) | |||
| @@ -2,7 +2,8 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !gccgo | |||
| //go:build gc | |||
| // +build gc | |||
| #include "textflag.h" | |||
| @@ -2,7 +2,8 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !gccgo | |||
| //go:build gc | |||
| // +build gc | |||
| #include "textflag.h" | |||
| @@ -2,7 +2,8 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !gccgo | |||
| //go:build gc | |||
| // +build gc | |||
| #include "textflag.h" | |||
| @@ -2,9 +2,10 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build linux && arm64 && gc | |||
| // +build linux | |||
| // +build arm64 | |||
| // +build !gccgo | |||
| // +build gc | |||
| #include "textflag.h" | |||
| @@ -2,9 +2,10 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build linux && (mips64 || mips64le) && gc | |||
| // +build linux | |||
| // +build mips64 mips64le | |||
| // +build !gccgo | |||
| // +build gc | |||
| #include "textflag.h" | |||
| @@ -2,9 +2,10 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build linux && (mips || mipsle) && gc | |||
| // +build linux | |||
| // +build mips mipsle | |||
| // +build !gccgo | |||
| // +build gc | |||
| #include "textflag.h" | |||
| @@ -2,9 +2,10 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build linux && (ppc64 || ppc64le) && gc | |||
| // +build linux | |||
| // +build ppc64 ppc64le | |||
| // +build !gccgo | |||
| // +build gc | |||
| #include "textflag.h" | |||
| @@ -2,7 +2,9 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build riscv64,!gccgo | |||
| //go:build riscv64 && gc | |||
| // +build riscv64 | |||
| // +build gc | |||
| #include "textflag.h" | |||
| @@ -2,9 +2,10 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build s390x | |||
| //go:build linux && s390x && gc | |||
| // +build linux | |||
| // +build !gccgo | |||
| // +build s390x | |||
| // +build gc | |||
| #include "textflag.h" | |||
| @@ -1,29 +0,0 @@ | |||
| // Copyright 2013 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !gccgo | |||
| #include "textflag.h" | |||
| // | |||
| // System call support for ARM, NetBSD | |||
| // | |||
| // Just jump to package syscall's implementation for all these functions. | |||
| // The runtime may know about them. | |||
| TEXT ·Syscall(SB),NOSPLIT,$0-28 | |||
| B syscall·Syscall(SB) | |||
| TEXT ·Syscall6(SB),NOSPLIT,$0-40 | |||
| B syscall·Syscall6(SB) | |||
| TEXT ·Syscall9(SB),NOSPLIT,$0-52 | |||
| B syscall·Syscall9(SB) | |||
| TEXT ·RawSyscall(SB),NOSPLIT,$0-28 | |||
| B syscall·RawSyscall(SB) | |||
| TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 | |||
| B syscall·RawSyscall6(SB) | |||
| @@ -1,29 +0,0 @@ | |||
| // Copyright 2019 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !gccgo | |||
| #include "textflag.h" | |||
| // | |||
| // System call support for ARM64, NetBSD | |||
| // | |||
| // Just jump to package syscall's implementation for all these functions. | |||
| // The runtime may know about them. | |||
| TEXT ·Syscall(SB),NOSPLIT,$0-56 | |||
| B syscall·Syscall(SB) | |||
| TEXT ·Syscall6(SB),NOSPLIT,$0-80 | |||
| B syscall·Syscall6(SB) | |||
| TEXT ·Syscall9(SB),NOSPLIT,$0-104 | |||
| B syscall·Syscall9(SB) | |||
| TEXT ·RawSyscall(SB),NOSPLIT,$0-56 | |||
| B syscall·RawSyscall(SB) | |||
| TEXT ·RawSyscall6(SB),NOSPLIT,$0-80 | |||
| B syscall·RawSyscall6(SB) | |||
| @@ -1,29 +0,0 @@ | |||
| // Copyright 2009 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !gccgo | |||
| #include "textflag.h" | |||
| // | |||
| // System call support for 386, OpenBSD | |||
| // | |||
| // Just jump to package syscall's implementation for all these functions. | |||
| // The runtime may know about them. | |||
| TEXT ·Syscall(SB),NOSPLIT,$0-28 | |||
| JMP syscall·Syscall(SB) | |||
| TEXT ·Syscall6(SB),NOSPLIT,$0-40 | |||
| JMP syscall·Syscall6(SB) | |||
| TEXT ·Syscall9(SB),NOSPLIT,$0-52 | |||
| JMP syscall·Syscall9(SB) | |||
| TEXT ·RawSyscall(SB),NOSPLIT,$0-28 | |||
| JMP syscall·RawSyscall(SB) | |||
| TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 | |||
| JMP syscall·RawSyscall6(SB) | |||
| @@ -1,29 +0,0 @@ | |||
| // Copyright 2017 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !gccgo | |||
| #include "textflag.h" | |||
| // | |||
| // System call support for ARM, OpenBSD | |||
| // | |||
| // Just jump to package syscall's implementation for all these functions. | |||
| // The runtime may know about them. | |||
| TEXT ·Syscall(SB),NOSPLIT,$0-28 | |||
| B syscall·Syscall(SB) | |||
| TEXT ·Syscall6(SB),NOSPLIT,$0-40 | |||
| B syscall·Syscall6(SB) | |||
| TEXT ·Syscall9(SB),NOSPLIT,$0-52 | |||
| B syscall·Syscall9(SB) | |||
| TEXT ·RawSyscall(SB),NOSPLIT,$0-28 | |||
| B syscall·RawSyscall(SB) | |||
| TEXT ·RawSyscall6(SB),NOSPLIT,$0-40 | |||
| B syscall·RawSyscall6(SB) | |||
| @@ -2,12 +2,13 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !gccgo | |||
| //go:build gc | |||
| // +build gc | |||
| #include "textflag.h" | |||
| // | |||
| // System call support for arm64, OpenBSD | |||
| // System call support for mips64, OpenBSD | |||
| // | |||
| // Just jump to package syscall's implementation for all these functions. | |||
| @@ -2,7 +2,8 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build !gccgo | |||
| //go:build gc | |||
| // +build gc | |||
| #include "textflag.h" | |||
| @@ -0,0 +1,426 @@ | |||
| // Copyright 2020 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build zos && s390x && gc | |||
| // +build zos | |||
| // +build s390x | |||
| // +build gc | |||
| #include "textflag.h" | |||
| #define PSALAA 1208(R0) | |||
| #define GTAB64(x) 80(x) | |||
| #define LCA64(x) 88(x) | |||
| #define CAA(x) 8(x) | |||
| #define EDCHPXV(x) 1016(x) // in the CAA | |||
| #define SAVSTACK_ASYNC(x) 336(x) // in the LCA | |||
| // SS_*, where x=SAVSTACK_ASYNC | |||
| #define SS_LE(x) 0(x) | |||
| #define SS_GO(x) 8(x) | |||
| #define SS_ERRNO(x) 16(x) | |||
| #define SS_ERRNOJR(x) 20(x) | |||
| #define LE_CALL BYTE $0x0D; BYTE $0x76; // BL R7, R6 | |||
| TEXT ·clearErrno(SB),NOSPLIT,$0-0 | |||
| BL addrerrno<>(SB) | |||
| MOVD $0, 0(R3) | |||
| RET | |||
| // Returns the address of errno in R3. | |||
| TEXT addrerrno<>(SB),NOSPLIT|NOFRAME,$0-0 | |||
| // Get library control area (LCA). | |||
| MOVW PSALAA, R8 | |||
| MOVD LCA64(R8), R8 | |||
| // Get __errno FuncDesc. | |||
| MOVD CAA(R8), R9 | |||
| MOVD EDCHPXV(R9), R9 | |||
| ADD $(0x156*16), R9 | |||
| LMG 0(R9), R5, R6 | |||
| // Switch to saved LE stack. | |||
| MOVD SAVSTACK_ASYNC(R8), R9 | |||
| MOVD 0(R9), R4 | |||
| MOVD $0, 0(R9) | |||
| // Call __errno function. | |||
| LE_CALL | |||
| NOPH | |||
| // Switch back to Go stack. | |||
| XOR R0, R0 // Restore R0 to $0. | |||
| MOVD R4, 0(R9) // Save stack pointer. | |||
| RET | |||
| TEXT ·syscall_syscall(SB),NOSPLIT,$0-56 | |||
| BL runtime·entersyscall(SB) | |||
| MOVD a1+8(FP), R1 | |||
| MOVD a2+16(FP), R2 | |||
| MOVD a3+24(FP), R3 | |||
| // Get library control area (LCA). | |||
| MOVW PSALAA, R8 | |||
| MOVD LCA64(R8), R8 | |||
| // Get function. | |||
| MOVD CAA(R8), R9 | |||
| MOVD EDCHPXV(R9), R9 | |||
| MOVD trap+0(FP), R5 | |||
| SLD $4, R5 | |||
| ADD R5, R9 | |||
| LMG 0(R9), R5, R6 | |||
| // Restore LE stack. | |||
| MOVD SAVSTACK_ASYNC(R8), R9 | |||
| MOVD 0(R9), R4 | |||
| MOVD $0, 0(R9) | |||
| // Call function. | |||
| LE_CALL | |||
| NOPH | |||
| XOR R0, R0 // Restore R0 to $0. | |||
| MOVD R4, 0(R9) // Save stack pointer. | |||
| MOVD R3, r1+32(FP) | |||
| MOVD R0, r2+40(FP) | |||
| MOVD R0, err+48(FP) | |||
| MOVW R3, R4 | |||
| CMP R4, $-1 | |||
| BNE done | |||
| BL addrerrno<>(SB) | |||
| MOVWZ 0(R3), R3 | |||
| MOVD R3, err+48(FP) | |||
| done: | |||
| BL runtime·exitsyscall(SB) | |||
| RET | |||
| TEXT ·syscall_rawsyscall(SB),NOSPLIT,$0-56 | |||
| MOVD a1+8(FP), R1 | |||
| MOVD a2+16(FP), R2 | |||
| MOVD a3+24(FP), R3 | |||
| // Get library control area (LCA). | |||
| MOVW PSALAA, R8 | |||
| MOVD LCA64(R8), R8 | |||
| // Get function. | |||
| MOVD CAA(R8), R9 | |||
| MOVD EDCHPXV(R9), R9 | |||
| MOVD trap+0(FP), R5 | |||
| SLD $4, R5 | |||
| ADD R5, R9 | |||
| LMG 0(R9), R5, R6 | |||
| // Restore LE stack. | |||
| MOVD SAVSTACK_ASYNC(R8), R9 | |||
| MOVD 0(R9), R4 | |||
| MOVD $0, 0(R9) | |||
| // Call function. | |||
| LE_CALL | |||
| NOPH | |||
| XOR R0, R0 // Restore R0 to $0. | |||
| MOVD R4, 0(R9) // Save stack pointer. | |||
| MOVD R3, r1+32(FP) | |||
| MOVD R0, r2+40(FP) | |||
| MOVD R0, err+48(FP) | |||
| MOVW R3, R4 | |||
| CMP R4, $-1 | |||
| BNE done | |||
| BL addrerrno<>(SB) | |||
| MOVWZ 0(R3), R3 | |||
| MOVD R3, err+48(FP) | |||
| done: | |||
| RET | |||
| TEXT ·syscall_syscall6(SB),NOSPLIT,$0-80 | |||
| BL runtime·entersyscall(SB) | |||
| MOVD a1+8(FP), R1 | |||
| MOVD a2+16(FP), R2 | |||
| MOVD a3+24(FP), R3 | |||
| // Get library control area (LCA). | |||
| MOVW PSALAA, R8 | |||
| MOVD LCA64(R8), R8 | |||
| // Get function. | |||
| MOVD CAA(R8), R9 | |||
| MOVD EDCHPXV(R9), R9 | |||
| MOVD trap+0(FP), R5 | |||
| SLD $4, R5 | |||
| ADD R5, R9 | |||
| LMG 0(R9), R5, R6 | |||
| // Restore LE stack. | |||
| MOVD SAVSTACK_ASYNC(R8), R9 | |||
| MOVD 0(R9), R4 | |||
| MOVD $0, 0(R9) | |||
| // Fill in parameter list. | |||
| MOVD a4+32(FP), R12 | |||
| MOVD R12, (2176+24)(R4) | |||
| MOVD a5+40(FP), R12 | |||
| MOVD R12, (2176+32)(R4) | |||
| MOVD a6+48(FP), R12 | |||
| MOVD R12, (2176+40)(R4) | |||
| // Call function. | |||
| LE_CALL | |||
| NOPH | |||
| XOR R0, R0 // Restore R0 to $0. | |||
| MOVD R4, 0(R9) // Save stack pointer. | |||
| MOVD R3, r1+56(FP) | |||
| MOVD R0, r2+64(FP) | |||
| MOVD R0, err+72(FP) | |||
| MOVW R3, R4 | |||
| CMP R4, $-1 | |||
| BNE done | |||
| BL addrerrno<>(SB) | |||
| MOVWZ 0(R3), R3 | |||
| MOVD R3, err+72(FP) | |||
| done: | |||
| BL runtime·exitsyscall(SB) | |||
| RET | |||
| TEXT ·syscall_rawsyscall6(SB),NOSPLIT,$0-80 | |||
| MOVD a1+8(FP), R1 | |||
| MOVD a2+16(FP), R2 | |||
| MOVD a3+24(FP), R3 | |||
| // Get library control area (LCA). | |||
| MOVW PSALAA, R8 | |||
| MOVD LCA64(R8), R8 | |||
| // Get function. | |||
| MOVD CAA(R8), R9 | |||
| MOVD EDCHPXV(R9), R9 | |||
| MOVD trap+0(FP), R5 | |||
| SLD $4, R5 | |||
| ADD R5, R9 | |||
| LMG 0(R9), R5, R6 | |||
| // Restore LE stack. | |||
| MOVD SAVSTACK_ASYNC(R8), R9 | |||
| MOVD 0(R9), R4 | |||
| MOVD $0, 0(R9) | |||
| // Fill in parameter list. | |||
| MOVD a4+32(FP), R12 | |||
| MOVD R12, (2176+24)(R4) | |||
| MOVD a5+40(FP), R12 | |||
| MOVD R12, (2176+32)(R4) | |||
| MOVD a6+48(FP), R12 | |||
| MOVD R12, (2176+40)(R4) | |||
| // Call function. | |||
| LE_CALL | |||
| NOPH | |||
| XOR R0, R0 // Restore R0 to $0. | |||
| MOVD R4, 0(R9) // Save stack pointer. | |||
| MOVD R3, r1+56(FP) | |||
| MOVD R0, r2+64(FP) | |||
| MOVD R0, err+72(FP) | |||
| MOVW R3, R4 | |||
| CMP R4, $-1 | |||
| BNE done | |||
| BL ·rrno<>(SB) | |||
| MOVWZ 0(R3), R3 | |||
| MOVD R3, err+72(FP) | |||
| done: | |||
| RET | |||
| TEXT ·syscall_syscall9(SB),NOSPLIT,$0 | |||
| BL runtime·entersyscall(SB) | |||
| MOVD a1+8(FP), R1 | |||
| MOVD a2+16(FP), R2 | |||
| MOVD a3+24(FP), R3 | |||
| // Get library control area (LCA). | |||
| MOVW PSALAA, R8 | |||
| MOVD LCA64(R8), R8 | |||
| // Get function. | |||
| MOVD CAA(R8), R9 | |||
| MOVD EDCHPXV(R9), R9 | |||
| MOVD trap+0(FP), R5 | |||
| SLD $4, R5 | |||
| ADD R5, R9 | |||
| LMG 0(R9), R5, R6 | |||
| // Restore LE stack. | |||
| MOVD SAVSTACK_ASYNC(R8), R9 | |||
| MOVD 0(R9), R4 | |||
| MOVD $0, 0(R9) | |||
| // Fill in parameter list. | |||
| MOVD a4+32(FP), R12 | |||
| MOVD R12, (2176+24)(R4) | |||
| MOVD a5+40(FP), R12 | |||
| MOVD R12, (2176+32)(R4) | |||
| MOVD a6+48(FP), R12 | |||
| MOVD R12, (2176+40)(R4) | |||
| MOVD a7+56(FP), R12 | |||
| MOVD R12, (2176+48)(R4) | |||
| MOVD a8+64(FP), R12 | |||
| MOVD R12, (2176+56)(R4) | |||
| MOVD a9+72(FP), R12 | |||
| MOVD R12, (2176+64)(R4) | |||
| // Call function. | |||
| LE_CALL | |||
| NOPH | |||
| XOR R0, R0 // Restore R0 to $0. | |||
| MOVD R4, 0(R9) // Save stack pointer. | |||
| MOVD R3, r1+80(FP) | |||
| MOVD R0, r2+88(FP) | |||
| MOVD R0, err+96(FP) | |||
| MOVW R3, R4 | |||
| CMP R4, $-1 | |||
| BNE done | |||
| BL addrerrno<>(SB) | |||
| MOVWZ 0(R3), R3 | |||
| MOVD R3, err+96(FP) | |||
| done: | |||
| BL runtime·exitsyscall(SB) | |||
| RET | |||
| TEXT ·syscall_rawsyscall9(SB),NOSPLIT,$0 | |||
| MOVD a1+8(FP), R1 | |||
| MOVD a2+16(FP), R2 | |||
| MOVD a3+24(FP), R3 | |||
| // Get library control area (LCA). | |||
| MOVW PSALAA, R8 | |||
| MOVD LCA64(R8), R8 | |||
| // Get function. | |||
| MOVD CAA(R8), R9 | |||
| MOVD EDCHPXV(R9), R9 | |||
| MOVD trap+0(FP), R5 | |||
| SLD $4, R5 | |||
| ADD R5, R9 | |||
| LMG 0(R9), R5, R6 | |||
| // Restore LE stack. | |||
| MOVD SAVSTACK_ASYNC(R8), R9 | |||
| MOVD 0(R9), R4 | |||
| MOVD $0, 0(R9) | |||
| // Fill in parameter list. | |||
| MOVD a4+32(FP), R12 | |||
| MOVD R12, (2176+24)(R4) | |||
| MOVD a5+40(FP), R12 | |||
| MOVD R12, (2176+32)(R4) | |||
| MOVD a6+48(FP), R12 | |||
| MOVD R12, (2176+40)(R4) | |||
| MOVD a7+56(FP), R12 | |||
| MOVD R12, (2176+48)(R4) | |||
| MOVD a8+64(FP), R12 | |||
| MOVD R12, (2176+56)(R4) | |||
| MOVD a9+72(FP), R12 | |||
| MOVD R12, (2176+64)(R4) | |||
| // Call function. | |||
| LE_CALL | |||
| NOPH | |||
| XOR R0, R0 // Restore R0 to $0. | |||
| MOVD R4, 0(R9) // Save stack pointer. | |||
| MOVD R3, r1+80(FP) | |||
| MOVD R0, r2+88(FP) | |||
| MOVD R0, err+96(FP) | |||
| MOVW R3, R4 | |||
| CMP R4, $-1 | |||
| BNE done | |||
| BL addrerrno<>(SB) | |||
| MOVWZ 0(R3), R3 | |||
| MOVD R3, err+96(FP) | |||
| done: | |||
| RET | |||
| // func svcCall(fnptr unsafe.Pointer, argv *unsafe.Pointer, dsa *uint64) | |||
| TEXT ·svcCall(SB),NOSPLIT,$0 | |||
| BL runtime·save_g(SB) // Save g and stack pointer | |||
| MOVW PSALAA, R8 | |||
| MOVD LCA64(R8), R8 | |||
| MOVD SAVSTACK_ASYNC(R8), R9 | |||
| MOVD R15, 0(R9) | |||
| MOVD argv+8(FP), R1 // Move function arguments into registers | |||
| MOVD dsa+16(FP), g | |||
| MOVD fnptr+0(FP), R15 | |||
| BYTE $0x0D // Branch to function | |||
| BYTE $0xEF | |||
| BL runtime·load_g(SB) // Restore g and stack pointer | |||
| MOVW PSALAA, R8 | |||
| MOVD LCA64(R8), R8 | |||
| MOVD SAVSTACK_ASYNC(R8), R9 | |||
| MOVD 0(R9), R15 | |||
| RET | |||
| // func svcLoad(name *byte) unsafe.Pointer | |||
| TEXT ·svcLoad(SB),NOSPLIT,$0 | |||
| MOVD R15, R2 // Save go stack pointer | |||
| MOVD name+0(FP), R0 // Move SVC args into registers | |||
| MOVD $0x80000000, R1 | |||
| MOVD $0, R15 | |||
| BYTE $0x0A // SVC 08 LOAD | |||
| BYTE $0x08 | |||
| MOVW R15, R3 // Save return code from SVC | |||
| MOVD R2, R15 // Restore go stack pointer | |||
| CMP R3, $0 // Check SVC return code | |||
| BNE error | |||
| MOVD $-2, R3 // Reset last bit of entry point to zero | |||
| AND R0, R3 | |||
| MOVD R3, addr+8(FP) // Return entry point returned by SVC | |||
| CMP R0, R3 // Check if last bit of entry point was set | |||
| BNE done | |||
| MOVD R15, R2 // Save go stack pointer | |||
| MOVD $0, R15 // Move SVC args into registers (entry point still in r0 from SVC 08) | |||
| BYTE $0x0A // SVC 09 DELETE | |||
| BYTE $0x09 | |||
| MOVD R2, R15 // Restore go stack pointer | |||
| error: | |||
| MOVD $0, addr+8(FP) // Return 0 on failure | |||
| done: | |||
| XOR R0, R0 // Reset r0 to 0 | |||
| RET | |||
| // func svcUnload(name *byte, fnptr unsafe.Pointer) int64 | |||
| TEXT ·svcUnload(SB),NOSPLIT,$0 | |||
| MOVD R15, R2 // Save go stack pointer | |||
| MOVD name+0(FP), R0 // Move SVC args into registers | |||
| MOVD addr+8(FP), R15 | |||
| BYTE $0x0A // SVC 09 | |||
| BYTE $0x09 | |||
| XOR R0, R0 // Reset r0 to 0 | |||
| MOVD R15, R1 // Save SVC return code | |||
| MOVD R2, R15 // Restore go stack pointer | |||
| MOVD R1, rc+0(FP) // Return SVC return code | |||
| RET | |||
| // func gettid() uint64 | |||
| TEXT ·gettid(SB), NOSPLIT, $0 | |||
| // Get library control area (LCA). | |||
| MOVW PSALAA, R8 | |||
| MOVD LCA64(R8), R8 | |||
| // Get CEECAATHDID | |||
| MOVD CAA(R8), R9 | |||
| MOVD 0x3D0(R9), R9 | |||
| MOVD R9, ret+0(FP) | |||
| RET | |||
| @@ -2,6 +2,7 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build freebsd | |||
| // +build freebsd | |||
| package unix | |||
| @@ -2,7 +2,8 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris | |||
| //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos | |||
| // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos | |||
| package unix | |||
| @@ -2,8 +2,8 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build aix | |||
| // +build ppc | |||
| //go:build aix && ppc | |||
| // +build aix,ppc | |||
| // Functions to access/create device major and minor numbers matching the | |||
| // encoding used by AIX. | |||
| @@ -2,8 +2,8 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build aix | |||
| // +build ppc64 | |||
| //go:build aix && ppc64 | |||
| // +build aix,ppc64 | |||
| // Functions to access/create device major and minor numbers matching the | |||
| // encoding used AIX. | |||
| @@ -0,0 +1,29 @@ | |||
| // Copyright 2020 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build zos && s390x | |||
| // +build zos,s390x | |||
| // Functions to access/create device major and minor numbers matching the | |||
| // encoding used by z/OS. | |||
| // | |||
| // The information below is extracted and adapted from <sys/stat.h> macros. | |||
| package unix | |||
| // Major returns the major component of a z/OS device number. | |||
| func Major(dev uint64) uint32 { | |||
| return uint32((dev >> 16) & 0x0000FFFF) | |||
| } | |||
| // Minor returns the minor component of a z/OS device number. | |||
| func Minor(dev uint64) uint32 { | |||
| return uint32(dev & 0x0000FFFF) | |||
| } | |||
| // Mkdev returns a z/OS device number generated from the given major and minor | |||
| // components. | |||
| func Mkdev(major, minor uint32) uint64 { | |||
| return (uint64(major) << 16) | uint64(minor) | |||
| } | |||
| @@ -2,6 +2,7 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris | |||
| // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris | |||
| package unix | |||
| @@ -2,7 +2,8 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // | |||
| // +build ppc64 s390x mips mips64 | |||
| //go:build armbe || arm64be || m68k || mips || mips64 || mips64p32 || ppc || ppc64 || s390 || s390x || shbe || sparc || sparc64 | |||
| // +build armbe arm64be m68k mips mips64 mips64p32 ppc ppc64 s390 s390x shbe sparc sparc64 | |||
| package unix | |||
| @@ -2,7 +2,8 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // | |||
| // +build 386 amd64 amd64p32 arm arm64 ppc64le mipsle mips64le riscv64 | |||
| //go:build 386 || amd64 || amd64p32 || alpha || arm || arm64 || mipsle || mips64le || mips64p32le || nios2 || ppc64le || riscv || riscv64 || sh | |||
| // +build 386 amd64 amd64p32 alpha arm arm64 mipsle mips64le mips64p32le nios2 ppc64le riscv riscv64 sh | |||
| package unix | |||
| @@ -2,7 +2,8 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris | |||
| //go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris || zos | |||
| // +build aix darwin dragonfly freebsd linux netbsd openbsd solaris zos | |||
| // Unix environment variables. | |||
| @@ -0,0 +1,221 @@ | |||
| // Copyright 2020 The Go Authors. All rights reserved. | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build zos && s390x | |||
| // +build zos,s390x | |||
| package unix | |||
| import ( | |||
| "sync" | |||
| ) | |||
| // This file simulates epoll on z/OS using poll. | |||
| // Analogous to epoll_event on Linux. | |||
| // TODO(neeilan): Pad is because the Linux kernel expects a 96-bit struct. We never pass this to the kernel; remove? | |||
| type EpollEvent struct { | |||
| Events uint32 | |||
| Fd int32 | |||
| Pad int32 | |||
| } | |||
| const ( | |||
| EPOLLERR = 0x8 | |||
| EPOLLHUP = 0x10 | |||
| EPOLLIN = 0x1 | |||
| EPOLLMSG = 0x400 | |||
| EPOLLOUT = 0x4 | |||
| EPOLLPRI = 0x2 | |||
| EPOLLRDBAND = 0x80 | |||
| EPOLLRDNORM = 0x40 | |||
| EPOLLWRBAND = 0x200 | |||
| EPOLLWRNORM = 0x100 | |||
| EPOLL_CTL_ADD = 0x1 | |||
| EPOLL_CTL_DEL = 0x2 | |||
| EPOLL_CTL_MOD = 0x3 | |||
| // The following constants are part of the epoll API, but represent | |||
| // currently unsupported functionality on z/OS. | |||
| // EPOLL_CLOEXEC = 0x80000 | |||
| // EPOLLET = 0x80000000 | |||
| // EPOLLONESHOT = 0x40000000 | |||
| // EPOLLRDHUP = 0x2000 // Typically used with edge-triggered notis | |||
| // EPOLLEXCLUSIVE = 0x10000000 // Exclusive wake-up mode | |||
| // EPOLLWAKEUP = 0x20000000 // Relies on Linux's BLOCK_SUSPEND capability | |||
| ) | |||
| // TODO(neeilan): We can eliminate these epToPoll / pToEpoll calls by using identical mask values for POLL/EPOLL | |||
| // constants where possible The lower 16 bits of epoll events (uint32) can fit any system poll event (int16). | |||
| // epToPollEvt converts epoll event field to poll equivalent. | |||
| // In epoll, Events is a 32-bit field, while poll uses 16 bits. | |||
| func epToPollEvt(events uint32) int16 { | |||
| var ep2p = map[uint32]int16{ | |||
| EPOLLIN: POLLIN, | |||
| EPOLLOUT: POLLOUT, | |||
| EPOLLHUP: POLLHUP, | |||
| EPOLLPRI: POLLPRI, | |||
| EPOLLERR: POLLERR, | |||
| } | |||
| var pollEvts int16 = 0 | |||
| for epEvt, pEvt := range ep2p { | |||
| if (events & epEvt) != 0 { | |||
| pollEvts |= pEvt | |||
| } | |||
| } | |||
| return pollEvts | |||
| } | |||
| // pToEpollEvt converts 16 bit poll event bitfields to 32-bit epoll event fields. | |||
| func pToEpollEvt(revents int16) uint32 { | |||
| var p2ep = map[int16]uint32{ | |||
| POLLIN: EPOLLIN, | |||
| POLLOUT: EPOLLOUT, | |||
| POLLHUP: EPOLLHUP, | |||
| POLLPRI: EPOLLPRI, | |||
| POLLERR: EPOLLERR, | |||
| } | |||
| var epollEvts uint32 = 0 | |||
| for pEvt, epEvt := range p2ep { | |||
| if (revents & pEvt) != 0 { | |||
| epollEvts |= epEvt | |||
| } | |||
| } | |||
| return epollEvts | |||
| } | |||
| // Per-process epoll implementation. | |||
| type epollImpl struct { | |||
| mu sync.Mutex | |||
| epfd2ep map[int]*eventPoll | |||
| nextEpfd int | |||
| } | |||
| // eventPoll holds a set of file descriptors being watched by the process. A process can have multiple epoll instances. | |||
| // On Linux, this is an in-kernel data structure accessed through a fd. | |||
| type eventPoll struct { | |||
| mu sync.Mutex | |||
| fds map[int]*EpollEvent | |||
| } | |||
| // epoll impl for this process. | |||
| var impl epollImpl = epollImpl{ | |||
| epfd2ep: make(map[int]*eventPoll), | |||
| nextEpfd: 0, | |||
| } | |||
| func (e *epollImpl) epollcreate(size int) (epfd int, err error) { | |||
| e.mu.Lock() | |||
| defer e.mu.Unlock() | |||
| epfd = e.nextEpfd | |||
| e.nextEpfd++ | |||
| e.epfd2ep[epfd] = &eventPoll{ | |||
| fds: make(map[int]*EpollEvent), | |||
| } | |||
| return epfd, nil | |||
| } | |||
| func (e *epollImpl) epollcreate1(flag int) (fd int, err error) { | |||
| return e.epollcreate(4) | |||
| } | |||
| func (e *epollImpl) epollctl(epfd int, op int, fd int, event *EpollEvent) (err error) { | |||
| e.mu.Lock() | |||
| defer e.mu.Unlock() | |||
| ep, ok := e.epfd2ep[epfd] | |||
| if !ok { | |||
| return EBADF | |||
| } | |||
| switch op { | |||
| case EPOLL_CTL_ADD: | |||
| // TODO(neeilan): When we make epfds and fds disjoint, detect epoll | |||
| // loops here (instances watching each other) and return ELOOP. | |||
| if _, ok := ep.fds[fd]; ok { | |||
| return EEXIST | |||
| } | |||
| ep.fds[fd] = event | |||
| case EPOLL_CTL_MOD: | |||
| if _, ok := ep.fds[fd]; !ok { | |||
| return ENOENT | |||
| } | |||
| ep.fds[fd] = event | |||
| case EPOLL_CTL_DEL: | |||
| if _, ok := ep.fds[fd]; !ok { | |||
| return ENOENT | |||
| } | |||
| delete(ep.fds, fd) | |||
| } | |||
| return nil | |||
| } | |||
| // Must be called while holding ep.mu | |||
| func (ep *eventPoll) getFds() []int { | |||
| fds := make([]int, len(ep.fds)) | |||
| for fd := range ep.fds { | |||
| fds = append(fds, fd) | |||
| } | |||
| return fds | |||
| } | |||
| func (e *epollImpl) epollwait(epfd int, events []EpollEvent, msec int) (n int, err error) { | |||
| e.mu.Lock() // in [rare] case of concurrent epollcreate + epollwait | |||
| ep, ok := e.epfd2ep[epfd] | |||
| if !ok { | |||
| e.mu.Unlock() | |||
| return 0, EBADF | |||
| } | |||
| pollfds := make([]PollFd, 4) | |||
| for fd, epollevt := range ep.fds { | |||
| pollfds = append(pollfds, PollFd{Fd: int32(fd), Events: epToPollEvt(epollevt.Events)}) | |||
| } | |||
| e.mu.Unlock() | |||
| n, err = Poll(pollfds, msec) | |||
| if err != nil { | |||
| return n, err | |||
| } | |||
| i := 0 | |||
| for _, pFd := range pollfds { | |||
| if pFd.Revents != 0 { | |||
| events[i] = EpollEvent{Fd: pFd.Fd, Events: pToEpollEvt(pFd.Revents)} | |||
| i++ | |||
| } | |||
| if i == n { | |||
| break | |||
| } | |||
| } | |||
| return n, nil | |||
| } | |||
| func EpollCreate(size int) (fd int, err error) { | |||
| return impl.epollcreate(size) | |||
| } | |||
| func EpollCreate1(flag int) (fd int, err error) { | |||
| return impl.epollcreate1(flag) | |||
| } | |||
| func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) { | |||
| return impl.epollctl(epfd, op, fd, event) | |||
| } | |||
| // Because EpollWait mutates events, the caller is expected to coordinate | |||
| // concurrent access if calling with the same epfd from multiple goroutines. | |||
| func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) { | |||
| return impl.epollwait(epfd, events, msec) | |||
| } | |||
| @@ -2,6 +2,7 @@ | |||
| // Use of this source code is governed by a BSD-style | |||
| // license that can be found in the LICENSE file. | |||
| //go:build dragonfly || freebsd || linux || netbsd || openbsd | |||
| // +build dragonfly freebsd linux netbsd openbsd | |||
| package unix | |||