zhangmeng
2019-08-26 a0123f163eddcea3e6b9f9d36f1f3fb3aa2c835a
提交 | 用户 | age
3bd1f2 1 // Copyright 2016 Tom Thorogood. All rights reserved.
Z 2 // Use of this source code is governed by a
3 // Modified BSD License license that can be found in
4 // the LICENSE file.
5
6 package shm
7
8 import (
9     "os"
10     "sync/atomic"
11     "unsafe"
12
a0123f 13     "golang.org/x/sys/unix"
3bd1f2 14 )
Z 15
16 func CreateSimplex(name string, perm os.FileMode, blockCount, blockSize int) (*ReadWriteCloser, error) {
17     if blockSize&0x3f != 0 {
18         return nil, ErrNotMultipleOf64
19     }
20
a0123f 21     file, err := Open(name, unix.O_CREAT|unix.O_EXCL|unix.O_TRUNC|unix.O_RDWR, perm)
3bd1f2 22     if err != nil {
Z 23         return nil, err
24     }
25
26     defer file.Close()
27
28     fullBlockSize := blockHeaderSize + uint64(blockSize)
29     size := sharedHeaderSize + fullBlockSize*uint64(blockCount)
30
31     if err = file.Truncate(int64(size)); err != nil {
32         return nil, err
33     }
34
35     data, err := unix.Mmap(int(file.Fd()), 0, int(size), unix.PROT_READ|unix.PROT_WRITE, unix.MAP_SHARED)
36     if err != nil {
37         return nil, err
38     }
39
40     shared := (*sharedMem)(unsafe.Pointer(&data[0]))
41
42     /*
43      * memset already set:
44      *    shared.ReadStart, shared.ReadEnd = 0, 0
45      *    shared.WriteStart, shared.WriteEnd = 0, 0
46      *    shared.block[i].Size = 0
47      *    shared.block[i].DoneRead, shared.block[i].DoneWrite = 0, 0
48      */
49     *(*uint32)(&shared.BlockCount), *(*uint64)(&shared.BlockSize) = uint32(blockCount), uint64(blockSize)
50
a0123f 51     if err = ((*Semaphore)(&shared.SemSignal)).Init(0); err != nil {
3bd1f2 52         return nil, err
Z 53     }
54
a0123f 55     if err = ((*Semaphore)(&shared.SemAvail)).Init(0); err != nil {
3bd1f2 56         return nil, err
Z 57     }
58
59     for i := uint32(0); i < uint32(blockCount); i++ {
60         block := (*sharedBlock)(unsafe.Pointer(&data[sharedHeaderSize+uint64(i)*fullBlockSize]))
61
62         switch i {
63         case 0:
64             block.Next, *(*uint32)(&block.Prev) = 1, uint32(blockCount-1)
65         case uint32(blockCount - 1):
66             block.Next, *(*uint32)(&block.Prev) = 0, uint32(blockCount-2)
67         default:
68             *(*uint32)(&block.Next), *(*uint32)(&block.Prev) = i+1, i-1
69         }
70     }
71
72     atomic.StoreUint32((*uint32)(&shared.Version), version)
73
74     return &ReadWriteCloser{
75         name: name,
76
77         data:          data,
78         readShared:    shared,
79         writeShared:   shared,
80         size:          size,
81         fullBlockSize: fullBlockSize,
82
83         Flags: (*[len(shared.Flags)]uint32)(unsafe.Pointer(&shared.Flags[0])),
84     }, nil
85 }
86
87 func CreateDuplex(name string, perm os.FileMode, blockCount, blockSize int) (*ReadWriteCloser, error) {
88     if blockSize&0x3f != 0 {
89         return nil, ErrNotMultipleOf64
90     }
91
a0123f 92     file, err := Open(name, unix.O_CREAT|unix.O_EXCL|unix.O_TRUNC|unix.O_RDWR, perm)
3bd1f2 93     if err != nil {
Z 94         return nil, err
95     }
96
97     defer file.Close()
98
99     fullBlockSize := blockHeaderSize + uint64(blockSize)
100     sharedSize := sharedHeaderSize + fullBlockSize*uint64(blockCount)
101     size := 2 * sharedSize
102
103     if err = file.Truncate(int64(size)); err != nil {
104         return nil, err
105     }
106
107     data, err := unix.Mmap(int(file.Fd()), 0, int(size), unix.PROT_READ|unix.PROT_WRITE, unix.MAP_SHARED)
108     if err != nil {
109         return nil, err
110     }
111
112     for i := uint64(0); i < 2; i++ {
113         shared := (*sharedMem)(unsafe.Pointer(&data[i*sharedSize]))
114
115         /*
116          * memset already set:
117          *    shared.ReadStart, shared.ReadEnd = 0, 0
118          *    shared.WriteStart, shared.WriteEnd = 0, 0
119          *    shared.Blocks[i].Size = 0
120          *    shared.Blocks[i].DoneRead, shared.Blocks[i].DoneWrite = 0, 0
121          */
122         *(*uint32)(&shared.BlockCount), *(*uint64)(&shared.BlockSize) = uint32(blockCount), uint64(blockSize)
123
a0123f 124         if err = ((*Semaphore)(&shared.SemSignal)).Init(0); err != nil {
3bd1f2 125             return nil, err
Z 126         }
127
a0123f 128         if err = ((*Semaphore)(&shared.SemAvail)).Init(0); err != nil {
3bd1f2 129             return nil, err
Z 130         }
131
132         for j := uint32(0); j < uint32(blockCount); j++ {
133             block := (*sharedBlock)(unsafe.Pointer(&data[i*sharedSize+sharedHeaderSize+uint64(j)*fullBlockSize]))
134
135             switch j {
136             case 0:
137                 block.Next, *(*uint32)(&block.Prev) = 1, uint32(blockCount-1)
138             case uint32(blockCount - 1):
139                 block.Next, *(*uint32)(&block.Prev) = 0, uint32(blockCount-2)
140             default:
141                 *(*uint32)(&block.Next), *(*uint32)(&block.Prev) = j+1, j-1
142             }
143         }
144     }
145
146     readShared := (*sharedMem)(unsafe.Pointer(&data[0]))
147     atomic.StoreUint32((*uint32)(&readShared.Version), version)
148
149     return &ReadWriteCloser{
150         name: name,
151
152         data:          data,
153         readShared:    readShared,
154         writeShared:   (*sharedMem)(unsafe.Pointer(&data[sharedSize])),
155         size:          size,
156         fullBlockSize: fullBlockSize,
157
158         Flags: (*[len(readShared.Flags)]uint32)(unsafe.Pointer(&readShared.Flags[0])),
159     }, nil
160 }