1// Copyright 2017 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 aix || darwin || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris
6
7package poll
8
9import (
10	"internal/syscall/unix"
11	"io"
12	"sync/atomic"
13	"syscall"
14)
15
16// FD is a file descriptor. The net and os packages use this type as a
17// field of a larger type representing a network connection or OS file.
18type FD struct {
19	// Lock sysfd and serialize access to Read and Write methods.
20	fdmu fdMutex
21
22	// System file descriptor. Immutable until Close.
23	Sysfd int
24
25	// I/O poller.
26	pd pollDesc
27
28	// Writev cache.
29	iovecs *[]syscall.Iovec
30
31	// Semaphore signaled when file is closed.
32	csema uint32
33
34	// Non-zero if this file has been set to blocking mode.
35	isBlocking uint32
36
37	// Whether this is a streaming descriptor, as opposed to a
38	// packet-based descriptor like a UDP socket. Immutable.
39	IsStream bool
40
41	// Whether a zero byte read indicates EOF. This is false for a
42	// message based socket connection.
43	ZeroReadIsEOF bool
44
45	// Whether this is a file rather than a network socket.
46	isFile bool
47}
48
49// Init initializes the FD. The Sysfd field should already be set.
50// This can be called multiple times on a single FD.
51// The net argument is a network name from the net package (e.g., "tcp"),
52// or "file".
53// Set pollable to true if fd should be managed by runtime netpoll.
54func (fd *FD) Init(net string, pollable bool) error {
55	// We don't actually care about the various network types.
56	if net == "file" {
57		fd.isFile = true
58	}
59	if !pollable {
60		fd.isBlocking = 1
61		return nil
62	}
63	err := fd.pd.init(fd)
64	if err != nil {
65		// If we could not initialize the runtime poller,
66		// assume we are using blocking mode.
67		fd.isBlocking = 1
68	}
69	return err
70}
71
72// Destroy closes the file descriptor. This is called when there are
73// no remaining references.
74func (fd *FD) destroy() error {
75	// Poller may want to unregister fd in readiness notification mechanism,
76	// so this must be executed before CloseFunc.
77	fd.pd.close()
78
79	// We don't use ignoringEINTR here because POSIX does not define
80	// whether the descriptor is closed if close returns EINTR.
81	// If the descriptor is indeed closed, using a loop would race
82	// with some other goroutine opening a new descriptor.
83	// (The Linux kernel guarantees that it is closed on an EINTR error.)
84	err := CloseFunc(fd.Sysfd)
85
86	fd.Sysfd = -1
87	runtime_Semrelease(&fd.csema)
88	return err
89}
90
91// Close closes the FD. The underlying file descriptor is closed by the
92// destroy method when there are no remaining references.
93func (fd *FD) Close() error {
94	if !fd.fdmu.increfAndClose() {
95		return errClosing(fd.isFile)
96	}
97
98	// Unblock any I/O.  Once it all unblocks and returns,
99	// so that it cannot be referring to fd.sysfd anymore,
100	// the final decref will close fd.sysfd. This should happen
101	// fairly quickly, since all the I/O is non-blocking, and any
102	// attempts to block in the pollDesc will return errClosing(fd.isFile).
103	fd.pd.evict()
104
105	// The call to decref will call destroy if there are no other
106	// references.
107	err := fd.decref()
108
109	// Wait until the descriptor is closed. If this was the only
110	// reference, it is already closed. Only wait if the file has
111	// not been set to blocking mode, as otherwise any current I/O
112	// may be blocking, and that would block the Close.
113	// No need for an atomic read of isBlocking, increfAndClose means
114	// we have exclusive access to fd.
115	if fd.isBlocking == 0 {
116		runtime_Semacquire(&fd.csema)
117	}
118
119	return err
120}
121
122// SetBlocking puts the file into blocking mode.
123func (fd *FD) SetBlocking() error {
124	if err := fd.incref(); err != nil {
125		return err
126	}
127	defer fd.decref()
128	// Atomic store so that concurrent calls to SetBlocking
129	// do not cause a race condition. isBlocking only ever goes
130	// from 0 to 1 so there is no real race here.
131	atomic.StoreUint32(&fd.isBlocking, 1)
132	return syscall.SetNonblock(fd.Sysfd, false)
133}
134
135// Darwin and FreeBSD can't read or write 2GB+ files at a time,
136// even on 64-bit systems.
137// The same is true of socket implementations on many systems.
138// See golang.org/issue/7812 and golang.org/issue/16266.
139// Use 1GB instead of, say, 2GB-1, to keep subsequent reads aligned.
140const maxRW = 1 << 30
141
142// Read implements io.Reader.
143func (fd *FD) Read(p []byte) (int, error) {
144	if err := fd.readLock(); err != nil {
145		return 0, err
146	}
147	defer fd.readUnlock()
148	if len(p) == 0 {
149		// If the caller wanted a zero byte read, return immediately
150		// without trying (but after acquiring the readLock).
151		// Otherwise syscall.Read returns 0, nil which looks like
152		// io.EOF.
153		// TODO(bradfitz): make it wait for readability? (Issue 15735)
154		return 0, nil
155	}
156	if err := fd.pd.prepareRead(fd.isFile); err != nil {
157		return 0, err
158	}
159	if fd.IsStream && len(p) > maxRW {
160		p = p[:maxRW]
161	}
162	for {
163		n, err := ignoringEINTRIO(syscall.Read, fd.Sysfd, p)
164		if err != nil {
165			n = 0
166			if err == syscall.EAGAIN && fd.pd.pollable() {
167				if err = fd.pd.waitRead(fd.isFile); err == nil {
168					continue
169				}
170			}
171		}
172		err = fd.eofError(n, err)
173		return n, err
174	}
175}
176
177// Pread wraps the pread system call.
178func (fd *FD) Pread(p []byte, off int64) (int, error) {
179	// Call incref, not readLock, because since pread specifies the
180	// offset it is independent from other reads.
181	// Similarly, using the poller doesn't make sense for pread.
182	if err := fd.incref(); err != nil {
183		return 0, err
184	}
185	if fd.IsStream && len(p) > maxRW {
186		p = p[:maxRW]
187	}
188	var (
189		n   int
190		err error
191	)
192	for {
193		n, err = syscall.Pread(fd.Sysfd, p, off)
194		if err != syscall.EINTR {
195			break
196		}
197	}
198	if err != nil {
199		n = 0
200	}
201	fd.decref()
202	err = fd.eofError(n, err)
203	return n, err
204}
205
206// ReadFrom wraps the recvfrom network call.
207func (fd *FD) ReadFrom(p []byte) (int, syscall.Sockaddr, error) {
208	if err := fd.readLock(); err != nil {
209		return 0, nil, err
210	}
211	defer fd.readUnlock()
212	if err := fd.pd.prepareRead(fd.isFile); err != nil {
213		return 0, nil, err
214	}
215	for {
216		n, sa, err := syscall.Recvfrom(fd.Sysfd, p, 0)
217		if err != nil {
218			if err == syscall.EINTR {
219				continue
220			}
221			n = 0
222			if err == syscall.EAGAIN && fd.pd.pollable() {
223				if err = fd.pd.waitRead(fd.isFile); err == nil {
224					continue
225				}
226			}
227		}
228		err = fd.eofError(n, err)
229		return n, sa, err
230	}
231}
232
233// ReadFromInet4 wraps the recvfrom network call for IPv4.
234func (fd *FD) ReadFromInet4(p []byte, from *syscall.SockaddrInet4) (int, error) {
235	if err := fd.readLock(); err != nil {
236		return 0, err
237	}
238	defer fd.readUnlock()
239	if err := fd.pd.prepareRead(fd.isFile); err != nil {
240		return 0, err
241	}
242	for {
243		n, err := unix.RecvfromInet4(fd.Sysfd, p, 0, from)
244		if err != nil {
245			if err == syscall.EINTR {
246				continue
247			}
248			n = 0
249			if err == syscall.EAGAIN && fd.pd.pollable() {
250				if err = fd.pd.waitRead(fd.isFile); err == nil {
251					continue
252				}
253			}
254		}
255		err = fd.eofError(n, err)
256		return n, err
257	}
258}
259
260// ReadFromInet6 wraps the recvfrom network call for IPv6.
261func (fd *FD) ReadFromInet6(p []byte, from *syscall.SockaddrInet6) (int, error) {
262	if err := fd.readLock(); err != nil {
263		return 0, err
264	}
265	defer fd.readUnlock()
266	if err := fd.pd.prepareRead(fd.isFile); err != nil {
267		return 0, err
268	}
269	for {
270		n, err := unix.RecvfromInet6(fd.Sysfd, p, 0, from)
271		if err != nil {
272			if err == syscall.EINTR {
273				continue
274			}
275			n = 0
276			if err == syscall.EAGAIN && fd.pd.pollable() {
277				if err = fd.pd.waitRead(fd.isFile); err == nil {
278					continue
279				}
280			}
281		}
282		err = fd.eofError(n, err)
283		return n, err
284	}
285}
286
287// ReadMsg wraps the recvmsg network call.
288func (fd *FD) ReadMsg(p []byte, oob []byte, flags int) (int, int, int, syscall.Sockaddr, error) {
289	if err := fd.readLock(); err != nil {
290		return 0, 0, 0, nil, err
291	}
292	defer fd.readUnlock()
293	if err := fd.pd.prepareRead(fd.isFile); err != nil {
294		return 0, 0, 0, nil, err
295	}
296	for {
297		n, oobn, sysflags, sa, err := syscall.Recvmsg(fd.Sysfd, p, oob, flags)
298		if err != nil {
299			if err == syscall.EINTR {
300				continue
301			}
302			// TODO(dfc) should n and oobn be set to 0
303			if err == syscall.EAGAIN && fd.pd.pollable() {
304				if err = fd.pd.waitRead(fd.isFile); err == nil {
305					continue
306				}
307			}
308		}
309		err = fd.eofError(n, err)
310		return n, oobn, sysflags, sa, err
311	}
312}
313
314// ReadMsgInet4 is ReadMsg, but specialized for syscall.SockaddrInet4.
315func (fd *FD) ReadMsgInet4(p []byte, oob []byte, flags int, sa4 *syscall.SockaddrInet4) (int, int, int, error) {
316	if err := fd.readLock(); err != nil {
317		return 0, 0, 0, err
318	}
319	defer fd.readUnlock()
320	if err := fd.pd.prepareRead(fd.isFile); err != nil {
321		return 0, 0, 0, err
322	}
323	for {
324		n, oobn, sysflags, err := unix.RecvmsgInet4(fd.Sysfd, p, oob, flags, sa4)
325		if err != nil {
326			if err == syscall.EINTR {
327				continue
328			}
329			// TODO(dfc) should n and oobn be set to 0
330			if err == syscall.EAGAIN && fd.pd.pollable() {
331				if err = fd.pd.waitRead(fd.isFile); err == nil {
332					continue
333				}
334			}
335		}
336		err = fd.eofError(n, err)
337		return n, oobn, sysflags, err
338	}
339}
340
341// ReadMsgInet6 is ReadMsg, but specialized for syscall.SockaddrInet6.
342func (fd *FD) ReadMsgInet6(p []byte, oob []byte, flags int, sa6 *syscall.SockaddrInet6) (int, int, int, error) {
343	if err := fd.readLock(); err != nil {
344		return 0, 0, 0, err
345	}
346	defer fd.readUnlock()
347	if err := fd.pd.prepareRead(fd.isFile); err != nil {
348		return 0, 0, 0, err
349	}
350	for {
351		n, oobn, sysflags, err := unix.RecvmsgInet6(fd.Sysfd, p, oob, flags, sa6)
352		if err != nil {
353			if err == syscall.EINTR {
354				continue
355			}
356			// TODO(dfc) should n and oobn be set to 0
357			if err == syscall.EAGAIN && fd.pd.pollable() {
358				if err = fd.pd.waitRead(fd.isFile); err == nil {
359					continue
360				}
361			}
362		}
363		err = fd.eofError(n, err)
364		return n, oobn, sysflags, err
365	}
366}
367
368// Write implements io.Writer.
369func (fd *FD) Write(p []byte) (int, error) {
370	if err := fd.writeLock(); err != nil {
371		return 0, err
372	}
373	defer fd.writeUnlock()
374	if err := fd.pd.prepareWrite(fd.isFile); err != nil {
375		return 0, err
376	}
377	var nn int
378	for {
379		max := len(p)
380		if fd.IsStream && max-nn > maxRW {
381			max = nn + maxRW
382		}
383		n, err := ignoringEINTRIO(syscall.Write, fd.Sysfd, p[nn:max])
384		if n > 0 {
385			nn += n
386		}
387		if nn == len(p) {
388			return nn, err
389		}
390		if err == syscall.EAGAIN && fd.pd.pollable() {
391			if err = fd.pd.waitWrite(fd.isFile); err == nil {
392				continue
393			}
394		}
395		if err != nil {
396			return nn, err
397		}
398		if n == 0 {
399			return nn, io.ErrUnexpectedEOF
400		}
401	}
402}
403
404// Pwrite wraps the pwrite system call.
405func (fd *FD) Pwrite(p []byte, off int64) (int, error) {
406	// Call incref, not writeLock, because since pwrite specifies the
407	// offset it is independent from other writes.
408	// Similarly, using the poller doesn't make sense for pwrite.
409	if err := fd.incref(); err != nil {
410		return 0, err
411	}
412	defer fd.decref()
413	var nn int
414	for {
415		max := len(p)
416		if fd.IsStream && max-nn > maxRW {
417			max = nn + maxRW
418		}
419		n, err := syscall.Pwrite(fd.Sysfd, p[nn:max], off+int64(nn))
420		if err == syscall.EINTR {
421			continue
422		}
423		if n > 0 {
424			nn += n
425		}
426		if nn == len(p) {
427			return nn, err
428		}
429		if err != nil {
430			return nn, err
431		}
432		if n == 0 {
433			return nn, io.ErrUnexpectedEOF
434		}
435	}
436}
437
438// WriteToInet4 wraps the sendto network call for IPv4 addresses.
439func (fd *FD) WriteToInet4(p []byte, sa *syscall.SockaddrInet4) (int, error) {
440	if err := fd.writeLock(); err != nil {
441		return 0, err
442	}
443	defer fd.writeUnlock()
444	if err := fd.pd.prepareWrite(fd.isFile); err != nil {
445		return 0, err
446	}
447	for {
448		err := unix.SendtoInet4(fd.Sysfd, p, 0, sa)
449		if err == syscall.EINTR {
450			continue
451		}
452		if err == syscall.EAGAIN && fd.pd.pollable() {
453			if err = fd.pd.waitWrite(fd.isFile); err == nil {
454				continue
455			}
456		}
457		if err != nil {
458			return 0, err
459		}
460		return len(p), nil
461	}
462}
463
464// WriteToInet6 wraps the sendto network call for IPv6 addresses.
465func (fd *FD) WriteToInet6(p []byte, sa *syscall.SockaddrInet6) (int, error) {
466	if err := fd.writeLock(); err != nil {
467		return 0, err
468	}
469	defer fd.writeUnlock()
470	if err := fd.pd.prepareWrite(fd.isFile); err != nil {
471		return 0, err
472	}
473	for {
474		err := unix.SendtoInet6(fd.Sysfd, p, 0, sa)
475		if err == syscall.EINTR {
476			continue
477		}
478		if err == syscall.EAGAIN && fd.pd.pollable() {
479			if err = fd.pd.waitWrite(fd.isFile); err == nil {
480				continue
481			}
482		}
483		if err != nil {
484			return 0, err
485		}
486		return len(p), nil
487	}
488}
489
490// WriteTo wraps the sendto network call.
491func (fd *FD) WriteTo(p []byte, sa syscall.Sockaddr) (int, error) {
492	if err := fd.writeLock(); err != nil {
493		return 0, err
494	}
495	defer fd.writeUnlock()
496	if err := fd.pd.prepareWrite(fd.isFile); err != nil {
497		return 0, err
498	}
499	for {
500		err := syscall.Sendto(fd.Sysfd, p, 0, sa)
501		if err == syscall.EINTR {
502			continue
503		}
504		if err == syscall.EAGAIN && fd.pd.pollable() {
505			if err = fd.pd.waitWrite(fd.isFile); err == nil {
506				continue
507			}
508		}
509		if err != nil {
510			return 0, err
511		}
512		return len(p), nil
513	}
514}
515
516// WriteMsg wraps the sendmsg network call.
517func (fd *FD) WriteMsg(p []byte, oob []byte, sa syscall.Sockaddr) (int, int, error) {
518	if err := fd.writeLock(); err != nil {
519		return 0, 0, err
520	}
521	defer fd.writeUnlock()
522	if err := fd.pd.prepareWrite(fd.isFile); err != nil {
523		return 0, 0, err
524	}
525	for {
526		n, err := syscall.SendmsgN(fd.Sysfd, p, oob, sa, 0)
527		if err == syscall.EINTR {
528			continue
529		}
530		if err == syscall.EAGAIN && fd.pd.pollable() {
531			if err = fd.pd.waitWrite(fd.isFile); err == nil {
532				continue
533			}
534		}
535		if err != nil {
536			return n, 0, err
537		}
538		return n, len(oob), err
539	}
540}
541
542// WriteMsgInet4 is WriteMsg specialized for syscall.SockaddrInet4.
543func (fd *FD) WriteMsgInet4(p []byte, oob []byte, sa *syscall.SockaddrInet4) (int, int, error) {
544	if err := fd.writeLock(); err != nil {
545		return 0, 0, err
546	}
547	defer fd.writeUnlock()
548	if err := fd.pd.prepareWrite(fd.isFile); err != nil {
549		return 0, 0, err
550	}
551	for {
552		n, err := unix.SendmsgNInet4(fd.Sysfd, p, oob, sa, 0)
553		if err == syscall.EINTR {
554			continue
555		}
556		if err == syscall.EAGAIN && fd.pd.pollable() {
557			if err = fd.pd.waitWrite(fd.isFile); err == nil {
558				continue
559			}
560		}
561		if err != nil {
562			return n, 0, err
563		}
564		return n, len(oob), err
565	}
566}
567
568// WriteMsgInet6 is WriteMsg specialized for syscall.SockaddrInet6.
569func (fd *FD) WriteMsgInet6(p []byte, oob []byte, sa *syscall.SockaddrInet6) (int, int, error) {
570	if err := fd.writeLock(); err != nil {
571		return 0, 0, err
572	}
573	defer fd.writeUnlock()
574	if err := fd.pd.prepareWrite(fd.isFile); err != nil {
575		return 0, 0, err
576	}
577	for {
578		n, err := unix.SendmsgNInet6(fd.Sysfd, p, oob, sa, 0)
579		if err == syscall.EINTR {
580			continue
581		}
582		if err == syscall.EAGAIN && fd.pd.pollable() {
583			if err = fd.pd.waitWrite(fd.isFile); err == nil {
584				continue
585			}
586		}
587		if err != nil {
588			return n, 0, err
589		}
590		return n, len(oob), err
591	}
592}
593
594// Accept wraps the accept network call.
595func (fd *FD) Accept() (int, syscall.Sockaddr, string, error) {
596	if err := fd.readLock(); err != nil {
597		return -1, nil, "", err
598	}
599	defer fd.readUnlock()
600
601	if err := fd.pd.prepareRead(fd.isFile); err != nil {
602		return -1, nil, "", err
603	}
604	for {
605		s, rsa, errcall, err := accept(fd.Sysfd)
606		if err == nil {
607			return s, rsa, "", err
608		}
609		switch err {
610		case syscall.EINTR:
611			continue
612		case syscall.EAGAIN:
613			if fd.pd.pollable() {
614				if err = fd.pd.waitRead(fd.isFile); err == nil {
615					continue
616				}
617			}
618		case syscall.ECONNABORTED:
619			// This means that a socket on the listen
620			// queue was closed before we Accept()ed it;
621			// it's a silly error, so try again.
622			continue
623		}
624		return -1, nil, errcall, err
625	}
626}
627
628// Seek wraps syscall.Seek.
629func (fd *FD) Seek(offset int64, whence int) (int64, error) {
630	if err := fd.incref(); err != nil {
631		return 0, err
632	}
633	defer fd.decref()
634	return syscall.Seek(fd.Sysfd, offset, whence)
635}
636
637// ReadDirent wraps syscall.ReadDirent.
638// We treat this like an ordinary system call rather than a call
639// that tries to fill the buffer.
640func (fd *FD) ReadDirent(buf []byte) (int, error) {
641	if err := fd.incref(); err != nil {
642		return 0, err
643	}
644	defer fd.decref()
645	for {
646		n, err := ignoringEINTRIO(syscall.ReadDirent, fd.Sysfd, buf)
647		if err != nil {
648			n = 0
649			if err == syscall.EAGAIN && fd.pd.pollable() {
650				if err = fd.pd.waitRead(fd.isFile); err == nil {
651					continue
652				}
653			}
654		}
655		// Do not call eofError; caller does not expect to see io.EOF.
656		return n, err
657	}
658}
659
660// Fchmod wraps syscall.Fchmod.
661func (fd *FD) Fchmod(mode uint32) error {
662	if err := fd.incref(); err != nil {
663		return err
664	}
665	defer fd.decref()
666	return ignoringEINTR(func() error {
667		return syscall.Fchmod(fd.Sysfd, mode)
668	})
669}
670
671// Fchdir wraps syscall.Fchdir.
672func (fd *FD) Fchdir() error {
673	if err := fd.incref(); err != nil {
674		return err
675	}
676	defer fd.decref()
677	return syscall.Fchdir(fd.Sysfd)
678}
679
680// Fstat wraps syscall.Fstat
681func (fd *FD) Fstat(s *syscall.Stat_t) error {
682	if err := fd.incref(); err != nil {
683		return err
684	}
685	defer fd.decref()
686	return ignoringEINTR(func() error {
687		return syscall.Fstat(fd.Sysfd, s)
688	})
689}
690
691// tryDupCloexec indicates whether F_DUPFD_CLOEXEC should be used.
692// If the kernel doesn't support it, this is set to 0.
693var tryDupCloexec = int32(1)
694
695// DupCloseOnExec dups fd and marks it close-on-exec.
696func DupCloseOnExec(fd int) (int, string, error) {
697	if syscall.F_DUPFD_CLOEXEC != 0 && atomic.LoadInt32(&tryDupCloexec) == 1 {
698		r0, e1 := fcntl(fd, syscall.F_DUPFD_CLOEXEC, 0)
699		if e1 == nil {
700			return r0, "", nil
701		}
702		switch e1.(syscall.Errno) {
703		case syscall.EINVAL, syscall.ENOSYS:
704			// Old kernel, or js/wasm (which returns
705			// ENOSYS). Fall back to the portable way from
706			// now on.
707			atomic.StoreInt32(&tryDupCloexec, 0)
708		default:
709			return -1, "fcntl", e1
710		}
711	}
712	return dupCloseOnExecOld(fd)
713}
714
715// dupCloseOnExecOld is the traditional way to dup an fd and
716// set its O_CLOEXEC bit, using two system calls.
717func dupCloseOnExecOld(fd int) (int, string, error) {
718	syscall.ForkLock.RLock()
719	defer syscall.ForkLock.RUnlock()
720	newfd, err := syscall.Dup(fd)
721	if err != nil {
722		return -1, "dup", err
723	}
724	syscall.CloseOnExec(newfd)
725	return newfd, "", nil
726}
727
728// Dup duplicates the file descriptor.
729func (fd *FD) Dup() (int, string, error) {
730	if err := fd.incref(); err != nil {
731		return -1, "", err
732	}
733	defer fd.decref()
734	return DupCloseOnExec(fd.Sysfd)
735}
736
737// On Unix variants only, expose the IO event for the net code.
738
739// WaitWrite waits until data can be read from fd.
740func (fd *FD) WaitWrite() error {
741	return fd.pd.waitWrite(fd.isFile)
742}
743
744// WriteOnce is for testing only. It makes a single write call.
745func (fd *FD) WriteOnce(p []byte) (int, error) {
746	if err := fd.writeLock(); err != nil {
747		return 0, err
748	}
749	defer fd.writeUnlock()
750	return ignoringEINTRIO(syscall.Write, fd.Sysfd, p)
751}
752
753// RawRead invokes the user-defined function f for a read operation.
754func (fd *FD) RawRead(f func(uintptr) bool) error {
755	if err := fd.readLock(); err != nil {
756		return err
757	}
758	defer fd.readUnlock()
759	if err := fd.pd.prepareRead(fd.isFile); err != nil {
760		return err
761	}
762	for {
763		if f(uintptr(fd.Sysfd)) {
764			return nil
765		}
766		if err := fd.pd.waitRead(fd.isFile); err != nil {
767			return err
768		}
769	}
770}
771
772// RawWrite invokes the user-defined function f for a write operation.
773func (fd *FD) RawWrite(f func(uintptr) bool) error {
774	if err := fd.writeLock(); err != nil {
775		return err
776	}
777	defer fd.writeUnlock()
778	if err := fd.pd.prepareWrite(fd.isFile); err != nil {
779		return err
780	}
781	for {
782		if f(uintptr(fd.Sysfd)) {
783			return nil
784		}
785		if err := fd.pd.waitWrite(fd.isFile); err != nil {
786			return err
787		}
788	}
789}
790
791// ignoringEINTRIO is like ignoringEINTR, but just for IO calls.
792func ignoringEINTRIO(fn func(fd int, p []byte) (int, error), fd int, p []byte) (int, error) {
793	for {
794		n, err := fn(fd, p)
795		if err != syscall.EINTR {
796			return n, err
797		}
798	}
799}
800