cubefs

Форк
0
/x
/
epoll_zos.go 
221 строка · 5.0 Кб
1
// Copyright 2020 The Go Authors. All rights reserved.
2
// Use of this source code is governed by a BSD-style
3
// license that can be found in the LICENSE file.
4

5
//go:build zos && s390x
6
// +build zos,s390x
7

8
package unix
9

10
import (
11
	"sync"
12
)
13

14
// This file simulates epoll on z/OS using poll.
15

16
// Analogous to epoll_event on Linux.
17
// TODO(neeilan): Pad is because the Linux kernel expects a 96-bit struct. We never pass this to the kernel; remove?
18
type EpollEvent struct {
19
	Events uint32
20
	Fd     int32
21
	Pad    int32
22
}
23

24
const (
25
	EPOLLERR      = 0x8
26
	EPOLLHUP      = 0x10
27
	EPOLLIN       = 0x1
28
	EPOLLMSG      = 0x400
29
	EPOLLOUT      = 0x4
30
	EPOLLPRI      = 0x2
31
	EPOLLRDBAND   = 0x80
32
	EPOLLRDNORM   = 0x40
33
	EPOLLWRBAND   = 0x200
34
	EPOLLWRNORM   = 0x100
35
	EPOLL_CTL_ADD = 0x1
36
	EPOLL_CTL_DEL = 0x2
37
	EPOLL_CTL_MOD = 0x3
38
	// The following constants are part of the epoll API, but represent
39
	// currently unsupported functionality on z/OS.
40
	// EPOLL_CLOEXEC  = 0x80000
41
	// EPOLLET        = 0x80000000
42
	// EPOLLONESHOT   = 0x40000000
43
	// EPOLLRDHUP     = 0x2000     // Typically used with edge-triggered notis
44
	// EPOLLEXCLUSIVE = 0x10000000 // Exclusive wake-up mode
45
	// EPOLLWAKEUP    = 0x20000000 // Relies on Linux's BLOCK_SUSPEND capability
46
)
47

48
// TODO(neeilan): We can eliminate these epToPoll / pToEpoll calls by using identical mask values for POLL/EPOLL
49
// constants where possible The lower 16 bits of epoll events (uint32) can fit any system poll event (int16).
50

51
// epToPollEvt converts epoll event field to poll equivalent.
52
// In epoll, Events is a 32-bit field, while poll uses 16 bits.
53
func epToPollEvt(events uint32) int16 {
54
	var ep2p = map[uint32]int16{
55
		EPOLLIN:  POLLIN,
56
		EPOLLOUT: POLLOUT,
57
		EPOLLHUP: POLLHUP,
58
		EPOLLPRI: POLLPRI,
59
		EPOLLERR: POLLERR,
60
	}
61

62
	var pollEvts int16 = 0
63
	for epEvt, pEvt := range ep2p {
64
		if (events & epEvt) != 0 {
65
			pollEvts |= pEvt
66
		}
67
	}
68

69
	return pollEvts
70
}
71

72
// pToEpollEvt converts 16 bit poll event bitfields to 32-bit epoll event fields.
73
func pToEpollEvt(revents int16) uint32 {
74
	var p2ep = map[int16]uint32{
75
		POLLIN:  EPOLLIN,
76
		POLLOUT: EPOLLOUT,
77
		POLLHUP: EPOLLHUP,
78
		POLLPRI: EPOLLPRI,
79
		POLLERR: EPOLLERR,
80
	}
81

82
	var epollEvts uint32 = 0
83
	for pEvt, epEvt := range p2ep {
84
		if (revents & pEvt) != 0 {
85
			epollEvts |= epEvt
86
		}
87
	}
88

89
	return epollEvts
90
}
91

92
// Per-process epoll implementation.
93
type epollImpl struct {
94
	mu       sync.Mutex
95
	epfd2ep  map[int]*eventPoll
96
	nextEpfd int
97
}
98

99
// eventPoll holds a set of file descriptors being watched by the process. A process can have multiple epoll instances.
100
// On Linux, this is an in-kernel data structure accessed through a fd.
101
type eventPoll struct {
102
	mu  sync.Mutex
103
	fds map[int]*EpollEvent
104
}
105

106
// epoll impl for this process.
107
var impl epollImpl = epollImpl{
108
	epfd2ep:  make(map[int]*eventPoll),
109
	nextEpfd: 0,
110
}
111

112
func (e *epollImpl) epollcreate(size int) (epfd int, err error) {
113
	e.mu.Lock()
114
	defer e.mu.Unlock()
115
	epfd = e.nextEpfd
116
	e.nextEpfd++
117

118
	e.epfd2ep[epfd] = &eventPoll{
119
		fds: make(map[int]*EpollEvent),
120
	}
121
	return epfd, nil
122
}
123

124
func (e *epollImpl) epollcreate1(flag int) (fd int, err error) {
125
	return e.epollcreate(4)
126
}
127

128
func (e *epollImpl) epollctl(epfd int, op int, fd int, event *EpollEvent) (err error) {
129
	e.mu.Lock()
130
	defer e.mu.Unlock()
131

132
	ep, ok := e.epfd2ep[epfd]
133
	if !ok {
134

135
		return EBADF
136
	}
137

138
	switch op {
139
	case EPOLL_CTL_ADD:
140
		// TODO(neeilan): When we make epfds and fds disjoint, detect epoll
141
		// loops here (instances watching each other) and return ELOOP.
142
		if _, ok := ep.fds[fd]; ok {
143
			return EEXIST
144
		}
145
		ep.fds[fd] = event
146
	case EPOLL_CTL_MOD:
147
		if _, ok := ep.fds[fd]; !ok {
148
			return ENOENT
149
		}
150
		ep.fds[fd] = event
151
	case EPOLL_CTL_DEL:
152
		if _, ok := ep.fds[fd]; !ok {
153
			return ENOENT
154
		}
155
		delete(ep.fds, fd)
156

157
	}
158
	return nil
159
}
160

161
// Must be called while holding ep.mu
162
func (ep *eventPoll) getFds() []int {
163
	fds := make([]int, len(ep.fds))
164
	for fd := range ep.fds {
165
		fds = append(fds, fd)
166
	}
167
	return fds
168
}
169

170
func (e *epollImpl) epollwait(epfd int, events []EpollEvent, msec int) (n int, err error) {
171
	e.mu.Lock() // in [rare] case of concurrent epollcreate + epollwait
172
	ep, ok := e.epfd2ep[epfd]
173

174
	if !ok {
175
		e.mu.Unlock()
176
		return 0, EBADF
177
	}
178

179
	pollfds := make([]PollFd, 4)
180
	for fd, epollevt := range ep.fds {
181
		pollfds = append(pollfds, PollFd{Fd: int32(fd), Events: epToPollEvt(epollevt.Events)})
182
	}
183
	e.mu.Unlock()
184

185
	n, err = Poll(pollfds, msec)
186
	if err != nil {
187
		return n, err
188
	}
189

190
	i := 0
191
	for _, pFd := range pollfds {
192
		if pFd.Revents != 0 {
193
			events[i] = EpollEvent{Fd: pFd.Fd, Events: pToEpollEvt(pFd.Revents)}
194
			i++
195
		}
196

197
		if i == n {
198
			break
199
		}
200
	}
201

202
	return n, nil
203
}
204

205
func EpollCreate(size int) (fd int, err error) {
206
	return impl.epollcreate(size)
207
}
208

209
func EpollCreate1(flag int) (fd int, err error) {
210
	return impl.epollcreate1(flag)
211
}
212

213
func EpollCtl(epfd int, op int, fd int, event *EpollEvent) (err error) {
214
	return impl.epollctl(epfd, op, fd, event)
215
}
216

217
// Because EpollWait mutates events, the caller is expected to coordinate
218
// concurrent access if calling with the same epfd from multiple goroutines.
219
func EpollWait(epfd int, events []EpollEvent, msec int) (n int, err error) {
220
	return impl.epollwait(epfd, events, msec)
221
}
222

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.