Skip to content

Commit 74550a8

Browse files
committed
Add syscall/syscall_getcpu
1 parent 01aad22 commit 74550a8

File tree

4 files changed

+115
-0
lines changed

4 files changed

+115
-0
lines changed
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
app
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# これは何?
2+
3+
syscall(2)を用いてgetcpu(2)を呼び出すサンプルです。
4+
5+
getcpu(2)システムコールはLinuxに存在しますが、glibc(GNU C ライブラリ)には対応するラッパー関数が提供されていません。
6+
そのため、他の多くのシステムコールのように単純に関数として呼び出すことができません。
7+
なので、syscall(2)を使って、glibcにラッパー関数が存在しないシステムコールを呼び出す必要があります。
8+
9+
```sh
10+
$ task
11+
task: [default] rm -f ./app
12+
task: [default] go build -o app .
13+
task: [default] ./app
14+
CPU: 10, NUMA: 0
15+
```
16+
17+
## C言語での実装
18+
19+
C言語では以下のようになります。
20+
21+
```c
22+
#include <stdio.h> // printf, perror
23+
#include <stdlib.h> // EXIT_SUCCESS, EXIT_FAILURE
24+
#include <unistd.h> // syscall
25+
#include <sys/syscall.h> // SYS_getcpu
26+
#include <errno.h> // errno
27+
28+
/**
29+
* @brief getcpu(2)をsyscall(2)を使って呼び出すサンプルプログラム
30+
*
31+
* このプログラムはsyscall(2)を使用してgetcpu(2)システムコールを直接呼び出し、
32+
* 現在のプロセスが実行されているCPU IDとNUMAノードを取得します。
33+
*
34+
* getcpu(2)のプロトタイプ:
35+
* int getcpu(unsigned *cpu, unsigned *node, struct getcpu_cache *tcache);
36+
*
37+
* @return 正常終了時は0、エラー時は-1
38+
*/
39+
int main(void)
40+
{
41+
unsigned int cpu = 0;
42+
unsigned int node = 0;
43+
44+
// getcpuシステムコールを呼び出す
45+
// 第3引数は通常NULLで良い(getcpu_cacheは非推奨)
46+
int result = syscall(SYS_getcpu, &cpu, &node, NULL);
47+
if (result == -1) {
48+
perror("syscall(SYS_getcpu) failed");
49+
return EXIT_FAILURE;
50+
}
51+
52+
printf("現在のCPU ID: %u\n", cpu);
53+
printf("現在のNUMAノード: %u\n", node);
54+
55+
return EXIT_SUCCESS;
56+
}
57+
```
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# https://taskfile.dev
2+
3+
version: '3'
4+
5+
tasks:
6+
default:
7+
cmds:
8+
- rm -f ./app
9+
- go build -o app .
10+
- ./app
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
package main
2+
3+
import (
4+
"fmt"
5+
"log"
6+
"unsafe"
7+
8+
"golang.org/x/sys/unix"
9+
)
10+
11+
func main() {
12+
log.SetFlags(0)
13+
14+
if err := run(); err != nil {
15+
log.Fatal(err)
16+
}
17+
}
18+
19+
func run() error {
20+
var (
21+
// syscall(2)のための引数とポインタ情報
22+
trap = uintptr(unix.SYS_GETCPU)
23+
cpu uint32
24+
node uint32
25+
ptrCpu = uintptr(unsafe.Pointer(&cpu))
26+
ptrNode = uintptr(unsafe.Pointer(&node))
27+
28+
// syscall(2)の結果
29+
r1 uintptr
30+
errno unix.Errno
31+
err error
32+
)
33+
// getcpu(2)はブロッキングしない単純なシステムコールなのでRawSyscall()を使っても問題無い
34+
r1, _, errno = unix.RawSyscall(trap, ptrCpu, ptrNode, uintptr(0))
35+
if errno != unix.Errno(0) {
36+
err = errno
37+
return err
38+
}
39+
40+
if int(r1) < 0 {
41+
return fmt.Errorf("getcpu syscall returned %d", r1)
42+
}
43+
44+
log.Printf("CPU: %d, NUMA: %d", cpu, node)
45+
46+
return nil
47+
}

0 commit comments

Comments
 (0)