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