Skip to content

Commit ade3c50

Browse files
authored
Merge pull request #7 from WeirdBob/master
Use IPC_INFO to get msgmax size (Linux support)
2 parents 5c31739 + d617574 commit ade3c50

File tree

8 files changed

+98
-31
lines changed

8 files changed

+98
-31
lines changed

cmd/ipcctl/main.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ func main() {
9090
if err != nil {
9191
log.Fatal(err)
9292
}
93+
default:
94+
log.Fatalf("Unsupported option %s\n", os.Args[1])
9395
}
9496
}
9597

common.go

Lines changed: 9 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
package ipc
22

3+
import (
4+
"math/bits"
5+
)
6+
37
const (
48
// https://code.woboq.org/userspace/glibc/sysdeps/unix/sysv/linux/bits/ipc.h.html
59
// Mode bits for `msgget', `semget', and `shmget'.
@@ -17,16 +21,14 @@ const (
1721
IPC_PRIVATE = 0 // Private key. NOTE: this value is of type __key_t, i.e., ((__key_t) 0)
1822
)
1923

20-
const (
21-
bufSize = 8192
22-
)
24+
var msgmax = 8192 // default size, will be overriden during init to match system msgmax
25+
var uintSize = bits.UintSize / 8 // size of a uint, arch dependent
2326

2427
type Msgbuf struct {
2528
Mtype uint
2629
Mtext []byte
2730
}
2831

29-
type msgbufInternal struct {
30-
Mtype uint
31-
Mtext [bufSize]byte
32-
}
32+
func Msgmax() int {
33+
return msgmax
34+
}

go.mod

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module github.com/siadat/ipc
2+
3+
go 1.14

init_linux.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package ipc
2+
3+
import (
4+
"syscall"
5+
"unsafe"
6+
)
7+
8+
func init() {
9+
var buf msginfo
10+
_, _, err := syscall.Syscall(
11+
syscall.SYS_MSGCTL,
12+
0,
13+
uintptr(IPC_INFO),
14+
uintptr(unsafe.Pointer(&buf)))
15+
if err != 0 {
16+
return // can't read current msg info, leave defaults
17+
}
18+
19+
msgmax = int(buf.msgmax)
20+
}
21+
22+
type msginfo struct {
23+
msgpool int32
24+
msgmap int32
25+
msgmax int32
26+
msgmnb int32
27+
msgmni int32
28+
msgssz int32
29+
msgtql int32
30+
msgseg uint16
31+
}

msgrcv.go

Lines changed: 28 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,45 @@
11
package ipc
22

33
import (
4+
"bytes"
5+
"encoding/binary"
6+
"fmt"
47
"syscall"
58
"unsafe"
69
)
710

811
// Msgrcv calls the msgrcv() syscall.
912
func Msgrcv(qid uint, msg *Msgbuf, flags uint) error {
10-
qbuf := msgbufInternal{
11-
Mtype: msg.Mtype,
12-
}
13-
lengthRead, _, err := syscall.Syscall6(syscall.SYS_MSGRCV,
13+
var buf = make([]byte, uintSize+msgmax)
14+
15+
lengthRead, _, errno := syscall.Syscall6(syscall.SYS_MSGRCV,
1416
uintptr(qid),
15-
uintptr(unsafe.Pointer(&qbuf)),
16-
uintptr(bufSize),
17+
uintptr(unsafe.Pointer(&buf[0])),
18+
uintptr(msgmax),
1719
uintptr(msg.Mtype),
1820
uintptr(flags),
1921
0,
2022
)
21-
if err != 0 {
22-
return err
23+
if errno != 0 {
24+
return errno
2325
}
24-
25-
msg.Mtype = qbuf.Mtype
26-
msg.Mtext = qbuf.Mtext[:lengthRead]
26+
buffer := bytes.NewBuffer(buf)
27+
switch uintSize {
28+
case 4:
29+
var mtype uint32
30+
err := binary.Write(buffer, binary.LittleEndian, &mtype)
31+
if err != nil {
32+
return fmt.Errorf("Can't write binary: %v", err)
33+
}
34+
msg.Mtype = uint(mtype)
35+
case 8:
36+
var mtype uint64
37+
err := binary.Write(buffer, binary.LittleEndian, &mtype)
38+
if err != nil {
39+
return fmt.Errorf("Can't write binary: %v", err)
40+
}
41+
msg.Mtype = uint(mtype)
42+
}
43+
msg.Mtext = buf[uintSize:uintSize+int(lengthRead)]
2744
return nil
2845
}

msgrcv_test.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,7 @@ func TestMsgrcv(t *testing.T) {
4141
if err != nil {
4242
panic(fmt.Sprintf("Failed to send message to ipc id %d: %s\n", qid, err))
4343
} else {
44-
fmt.Printf("Message %v send to ipc id %d\n", input, qid)
44+
fmt.Printf("Message %x send to ipc id %d\n", input, qid)
4545
}
4646

4747
qbuf := &ipc.Msgbuf{Mtype: 12}
@@ -51,7 +51,7 @@ func TestMsgrcv(t *testing.T) {
5151
if err != nil {
5252
panic(fmt.Sprintf("Failed to receive message to ipc id %d: %s\n", qid, err))
5353
} else {
54-
fmt.Printf("Message %v receive to ipc id %d\n", qbuf.Mtext, qid)
54+
fmt.Printf("Message %x receive to ipc id %d\n", qbuf.Mtext, qid)
5555
}
5656

5757
if !bytes.Equal(input, qbuf.Mtext) {

msgsnd.go

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,43 @@
11
package ipc
22

33
import (
4+
"bytes"
5+
"encoding/binary"
46
"fmt"
57
"syscall"
68
"unsafe"
79
)
810

911
// Msgsnd calls the msgsnd() syscall.
1012
func Msgsnd(qid uint, msg *Msgbuf, flags uint) error {
11-
if len(msg.Mtext) > bufSize {
12-
return fmt.Errorf("mtext is too large, %d > %d", len(msg.Mtext), bufSize)
13+
if len(msg.Mtext) > msgmax {
14+
return fmt.Errorf("mtext is too large, %d > %d", len(msg.Mtext), msgmax)
1315
}
14-
qbuf := msgbufInternal{
15-
Mtype: msg.Mtype,
16-
}
17-
copy(qbuf.Mtext[:], msg.Mtext)
1816

19-
_, _, err := syscall.Syscall6(syscall.SYS_MSGSND,
17+
buf := make([]byte, uintSize+msgmax)
18+
buffer := bytes.NewBuffer(buf)
19+
buffer.Reset()
20+
var err error
21+
switch uintSize {
22+
case 4:
23+
err = binary.Write(buffer, binary.LittleEndian, uint32(msg.Mtype))
24+
case 8:
25+
err = binary.Write(buffer, binary.LittleEndian, uint64(msg.Mtype))
26+
}
27+
if err != nil {
28+
return fmt.Errorf("Can't write binary: %v", err)
29+
}
30+
buffer.Write(msg.Mtext)
31+
_, _, errno := syscall.Syscall6(syscall.SYS_MSGSND,
2032
uintptr(qid),
21-
uintptr(unsafe.Pointer(&qbuf)),
33+
uintptr(unsafe.Pointer(&buf[0])),
2234
uintptr(len(msg.Mtext)),
2335
uintptr(flags),
2436
0,
2537
0,
2638
)
27-
if err != 0 {
28-
return err
39+
if errno != 0 {
40+
return errno
2941
}
3042
return nil
3143
}

msgsnd_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ func TestMsgsnd(t *testing.T) {
4040
t.Fatal(err)
4141
}
4242
}(qid)
43-
4443
mtext := "hello"
4544
done := make(chan struct{})
4645
go func() {
@@ -52,6 +51,7 @@ func TestMsgsnd(t *testing.T) {
5251
if want, got := mtext, string(qbuf.Mtext); want != got {
5352
t.Fatalf("want %#v, got %#v", want, got)
5453
}
54+
fmt.Printf("Received: %s\n", string(qbuf.Mtext))
5555
done <- struct{}{}
5656
}()
5757

0 commit comments

Comments
 (0)