| 提交 | 用户 | 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 | ||
| 156e61 | 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 | } | |