aboutsummaryrefslogtreecommitdiffstats
path: root/vendor/google.golang.org/grpc/internal/syscall/syscall_linux.go
blob: 43281a3e078db1af11c37a22c59e745dc9f67ca8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
// +build !appengine

/*
 *
 * Copyright 2018 gRPC authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 *
 */

// Package syscall provides functionalities that grpc uses to get low-level operating system
// stats/info.
package syscall

import (
    "fmt"
    "net"
    "syscall"
    "time"

    "golang.org/x/sys/unix"
    "google.golang.org/grpc/grpclog"
)

// GetCPUTime returns the how much CPU time has passed since the start of this process.
func GetCPUTime() int64 {
    var ts unix.Timespec
    if err := unix.ClockGettime(unix.CLOCK_PROCESS_CPUTIME_ID, &ts); err != nil {
        grpclog.Fatal(err)
    }
    return ts.Nano()
}

// Rusage is an alias for syscall.Rusage under linux non-appengine environment.
type Rusage syscall.Rusage

// GetRusage returns the resource usage of current process.
func GetRusage() (rusage *Rusage) {
    rusage = new(Rusage)
    syscall.Getrusage(syscall.RUSAGE_SELF, (*syscall.Rusage)(rusage))
    return
}

// CPUTimeDiff returns the differences of user CPU time and system CPU time used
// between two Rusage structs.
func CPUTimeDiff(first *Rusage, latest *Rusage) (float64, float64) {
    f := (*syscall.Rusage)(first)
    l := (*syscall.Rusage)(latest)
    var (
        utimeDiffs  = l.Utime.Sec - f.Utime.Sec
        utimeDiffus = l.Utime.Usec - f.Utime.Usec
        stimeDiffs  = l.Stime.Sec - f.Stime.Sec
        stimeDiffus = l.Stime.Usec - f.Stime.Usec
    )

    uTimeElapsed := float64(utimeDiffs) + float64(utimeDiffus)*1.0e-6
    sTimeElapsed := float64(stimeDiffs) + float64(stimeDiffus)*1.0e-6

    return uTimeElapsed, sTimeElapsed
}

// SetTCPUserTimeout sets the TCP user timeout on a connection's socket
func SetTCPUserTimeout(conn net.Conn, timeout time.Duration) error {
    tcpconn, ok := conn.(*net.TCPConn)
    if !ok {
        // not a TCP connection. exit early
        return nil
    }
    rawConn, err := tcpconn.SyscallConn()
    if err != nil {
        return fmt.Errorf("error getting raw connection: %v", err)
    }
    err = rawConn.Control(func(fd uintptr) {
        err = syscall.SetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_USER_TIMEOUT, int(timeout/time.Millisecond))
    })
    if err != nil {
        return fmt.Errorf("error setting option on socket: %v", err)
    }

    return nil
}

// GetTCPUserTimeout gets the TCP user timeout on a connection's socket
func GetTCPUserTimeout(conn net.Conn) (opt int, err error) {
    tcpconn, ok := conn.(*net.TCPConn)
    if !ok {
        err = fmt.Errorf("conn is not *net.TCPConn. got %T", conn)
        return
    }
    rawConn, err := tcpconn.SyscallConn()
    if err != nil {
        err = fmt.Errorf("error getting raw connection: %v", err)
        return
    }
    err = rawConn.Control(func(fd uintptr) {
        opt, err = syscall.GetsockoptInt(int(fd), syscall.IPPROTO_TCP, unix.TCP_USER_TIMEOUT)
    })
    if err != nil {
        err = fmt.Errorf("error getting option on socket: %v", err)
        return
    }

    return
}