55 * Copyright (C) 2005 Microsoft 
66 * Copyright (C) 2017-2021 WireGuard LLC. All Rights Reserved. 
77 */ 
8+ 
89package  winpipe
910
1011import  (
11- 	"errors" 
1212	"io" 
13+ 	"os" 
1314	"runtime" 
1415	"sync" 
1516	"sync/atomic" 
1617	"time" 
18+ 	"unsafe" 
1719
1820	"golang.org/x/sys/windows" 
1921)
2022
21- //sys cancelIoEx(file windows.Handle, o *windows.Overlapped) (err error) = CancelIoEx 
22- //sys createIoCompletionPort(file windows.Handle, port windows.Handle, key uintptr, threadCount uint32) (newport windows.Handle, err error) = CreateIoCompletionPort 
23- //sys getQueuedCompletionStatus(port windows.Handle, bytes *uint32, key *uintptr, o **ioOperation, timeout uint32) (err error) = GetQueuedCompletionStatus 
24- //sys setFileCompletionNotificationModes(h windows.Handle, flags uint8) (err error) = SetFileCompletionNotificationModes 
25- //sys wsaGetOverlappedResult(h windows.Handle, o *windows.Overlapped, bytes *uint32, wait bool, flags *uint32) (err error) = ws2_32.WSAGetOverlappedResult 
26- 
27- type  atomicBool  int32 
28- 
29- func  (b  * atomicBool ) isSet () bool  { return  atomic .LoadInt32 ((* int32 )(b )) !=  0  }
30- func  (b  * atomicBool ) setFalse ()   { atomic .StoreInt32 ((* int32 )(b ), 0 ) }
31- func  (b  * atomicBool ) setTrue ()    { atomic .StoreInt32 ((* int32 )(b ), 1 ) }
32- func  (b  * atomicBool ) swap (new  bool ) bool  {
33- 	var  newInt  int32 
34- 	if  new  {
35- 		newInt  =  1 
36- 	}
37- 	return  atomic .SwapInt32 ((* int32 )(b ), newInt ) ==  1 
38- }
39- 
40- const  (
41- 	cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS  =  1 
42- 	cFILE_SKIP_SET_EVENT_ON_HANDLE         =  2 
43- )
44- 
45- var  (
46- 	ErrFileClosed  =  errors .New ("file has already been closed" )
47- 	ErrTimeout     =  & timeoutError {}
48- )
49- 
50- type  timeoutError  struct {}
51- 
52- func  (e  * timeoutError ) Error () string    { return  "i/o timeout"  }
53- func  (e  * timeoutError ) Timeout () bool    { return  true  }
54- func  (e  * timeoutError ) Temporary () bool  { return  true  }
55- 
5623type  timeoutChan  chan  struct {}
5724
5825var  ioInitOnce  sync.Once 
@@ -71,21 +38,21 @@ type ioOperation struct {
7138}
7239
7340func  initIo () {
74- 	h , err  :=  createIoCompletionPort (windows .InvalidHandle , 0 , 0 , 0xffffffff )
41+ 	h , err  :=  windows . CreateIoCompletionPort (windows .InvalidHandle , 0 , 0 , 0 )
7542	if  err  !=  nil  {
7643		panic (err )
7744	}
7845	ioCompletionPort  =  h 
7946	go  ioCompletionProcessor (h )
8047}
8148
82- // win32File  implements Reader, Writer, and Closer on a Win32 handle without blocking in a syscall. 
49+ // file  implements Reader, Writer, and Closer on a Win32 handle without blocking in a syscall. 
8350// It takes ownership of this handle and will close it if it is garbage collected. 
84- type  win32File  struct  {
51+ type  file  struct  {
8552	handle         windows.Handle 
8653	wg             sync.WaitGroup 
8754	wgLock         sync.RWMutex 
88- 	closing        atomicBool 
55+ 	closing        uint32   // used as atomic boolean 
8956	socket         bool 
9057	readDeadline   deadlineHandler 
9158	writeDeadline  deadlineHandler 
@@ -96,18 +63,18 @@ type deadlineHandler struct {
9663	channel      timeoutChan 
9764	channelLock  sync.RWMutex 
9865	timer        * time.Timer 
99- 	timedout     atomicBool 
66+ 	timedout     uint32   // used as atomic boolean 
10067}
10168
102- // makeWin32File  makes a new win32File  from an existing file handle 
103- func  makeWin32File (h  windows.Handle ) (* win32File , error ) {
104- 	f  :=  & win32File {handle : h }
69+ // makeFile  makes a new file  from an existing file handle 
70+ func  makeFile (h  windows.Handle ) (* file , error ) {
71+ 	f  :=  & file {handle : h }
10572	ioInitOnce .Do (initIo )
106- 	_ , err  :=  createIoCompletionPort (h , ioCompletionPort , 0 , 0xffffffff )
73+ 	_ , err  :=  windows . CreateIoCompletionPort (h , ioCompletionPort , 0 , 0 )
10774	if  err  !=  nil  {
10875		return  nil , err 
10976	}
110- 	err  =  setFileCompletionNotificationModes (h , cFILE_SKIP_COMPLETION_PORT_ON_SUCCESS | cFILE_SKIP_SET_EVENT_ON_HANDLE )
77+ 	err  =  windows . SetFileCompletionNotificationModes (h , windows . FILE_SKIP_COMPLETION_PORT_ON_SUCCESS | windows . FILE_SKIP_SET_EVENT_ON_HANDLE )
11178	if  err  !=  nil  {
11279		return  nil , err 
11380	}
@@ -116,18 +83,14 @@ func makeWin32File(h windows.Handle) (*win32File, error) {
11683	return  f , nil 
11784}
11885
119- func  MakeOpenFile (h  windows.Handle ) (io.ReadWriteCloser , error ) {
120- 	return  makeWin32File (h )
121- }
122- 
12386// closeHandle closes the resources associated with a Win32 handle 
124- func  (f  * win32File ) closeHandle () {
87+ func  (f  * file ) closeHandle () {
12588	f .wgLock .Lock ()
12689	// Atomically set that we are closing, releasing the resources only once. 
127- 	if  ! f .closing . swap ( true )  {
90+ 	if  atomic . SwapUint32 ( & f .closing ,  1 )  ==   0  {
12891		f .wgLock .Unlock ()
12992		// cancel all IO and wait for it to complete 
130- 		cancelIoEx (f .handle , nil )
93+ 		windows . CancelIoEx (f .handle , nil )
13194		f .wg .Wait ()
13295		// at this point, no new IO can start 
13396		windows .Close (f .handle )
@@ -137,19 +100,19 @@ func (f *win32File) closeHandle() {
137100	}
138101}
139102
140- // Close closes a win32File . 
141- func  (f  * win32File ) Close () error  {
103+ // Close closes a file . 
104+ func  (f  * file ) Close () error  {
142105	f .closeHandle ()
143106	return  nil 
144107}
145108
146109// prepareIo prepares for a new IO operation. 
147110// The caller must call f.wg.Done() when the IO is finished, prior to Close() returning. 
148- func  (f  * win32File ) prepareIo () (* ioOperation , error ) {
111+ func  (f  * file ) prepareIo () (* ioOperation , error ) {
149112	f .wgLock .RLock ()
150- 	if  f .closing . isSet ()  {
113+ 	if  atomic . LoadUint32 ( & f .closing )  ==   1  {
151114		f .wgLock .RUnlock ()
152- 		return  nil , ErrFileClosed 
115+ 		return  nil , os . ErrClosed 
153116	}
154117	f .wg .Add (1 )
155118	f .wgLock .RUnlock ()
@@ -164,7 +127,7 @@ func ioCompletionProcessor(h windows.Handle) {
164127		var  bytes  uint32 
165128		var  key  uintptr 
166129		var  op  * ioOperation 
167- 		err  :=  getQueuedCompletionStatus (h , & bytes , & key , & op , windows .INFINITE )
130+ 		err  :=  windows . GetQueuedCompletionStatus (h , & bytes , & key , ( * * windows . Overlapped )( unsafe . Pointer ( & op )) , windows .INFINITE )
168131		if  op  ==  nil  {
169132			panic (err )
170133		}
@@ -174,13 +137,13 @@ func ioCompletionProcessor(h windows.Handle) {
174137
175138// asyncIo processes the return value from ReadFile or WriteFile, blocking until 
176139// the operation has actually completed. 
177- func  (f  * win32File ) asyncIo (c  * ioOperation , d  * deadlineHandler , bytes  uint32 , err  error ) (int , error ) {
140+ func  (f  * file ) asyncIo (c  * ioOperation , d  * deadlineHandler , bytes  uint32 , err  error ) (int , error ) {
178141	if  err  !=  windows .ERROR_IO_PENDING  {
179142		return  int (bytes ), err 
180143	}
181144
182- 	if  f .closing . isSet ()  {
183- 		cancelIoEx (f .handle , & c .o )
145+ 	if  atomic . LoadUint32 ( & f .closing )  ==   1  {
146+ 		windows . CancelIoEx (f .handle , & c .o )
184147	}
185148
186149	var  timeout  timeoutChan 
@@ -195,20 +158,20 @@ func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, er
195158	case  r  =  <- c .ch :
196159		err  =  r .err 
197160		if  err  ==  windows .ERROR_OPERATION_ABORTED  {
198- 			if  f .closing . isSet ()  {
199- 				err  =  ErrFileClosed 
161+ 			if  atomic . LoadUint32 ( & f .closing )  ==   1  {
162+ 				err  =  os . ErrClosed 
200163			}
201164		} else  if  err  !=  nil  &&  f .socket  {
202165			// err is from Win32. Query the overlapped structure to get the winsock error. 
203166			var  bytes , flags  uint32 
204- 			err  =  wsaGetOverlappedResult (f .handle , & c .o , & bytes , false , & flags )
167+ 			err  =  windows . WSAGetOverlappedResult (f .handle , & c .o , & bytes , false , & flags )
205168		}
206169	case  <- timeout :
207- 		cancelIoEx (f .handle , & c .o )
170+ 		windows . CancelIoEx (f .handle , & c .o )
208171		r  =  <- c .ch 
209172		err  =  r .err 
210173		if  err  ==  windows .ERROR_OPERATION_ABORTED  {
211- 			err  =  ErrTimeout 
174+ 			err  =  os . ErrDeadlineExceeded 
212175		}
213176	}
214177
@@ -220,15 +183,15 @@ func (f *win32File) asyncIo(c *ioOperation, d *deadlineHandler, bytes uint32, er
220183}
221184
222185// Read reads from a file handle. 
223- func  (f  * win32File ) Read (b  []byte ) (int , error ) {
186+ func  (f  * file ) Read (b  []byte ) (int , error ) {
224187	c , err  :=  f .prepareIo ()
225188	if  err  !=  nil  {
226189		return  0 , err 
227190	}
228191	defer  f .wg .Done ()
229192
230- 	if  f .readDeadline .timedout . isSet ()  {
231- 		return  0 , ErrTimeout 
193+ 	if  atomic . LoadUint32 ( & f .readDeadline .timedout )  ==   1  {
194+ 		return  0 , os . ErrDeadlineExceeded 
232195	}
233196
234197	var  bytes  uint32 
@@ -247,15 +210,15 @@ func (f *win32File) Read(b []byte) (int, error) {
247210}
248211
249212// Write writes to a file handle. 
250- func  (f  * win32File ) Write (b  []byte ) (int , error ) {
213+ func  (f  * file ) Write (b  []byte ) (int , error ) {
251214	c , err  :=  f .prepareIo ()
252215	if  err  !=  nil  {
253216		return  0 , err 
254217	}
255218	defer  f .wg .Done ()
256219
257- 	if  f .writeDeadline .timedout . isSet ()  {
258- 		return  0 , ErrTimeout 
220+ 	if  atomic . LoadUint32 ( & f .writeDeadline .timedout )  ==   1  {
221+ 		return  0 , os . ErrDeadlineExceeded 
259222	}
260223
261224	var  bytes  uint32 
@@ -265,19 +228,19 @@ func (f *win32File) Write(b []byte) (int, error) {
265228	return  n , err 
266229}
267230
268- func  (f  * win32File ) SetReadDeadline (deadline  time.Time ) error  {
231+ func  (f  * file ) SetReadDeadline (deadline  time.Time ) error  {
269232	return  f .readDeadline .set (deadline )
270233}
271234
272- func  (f  * win32File ) SetWriteDeadline (deadline  time.Time ) error  {
235+ func  (f  * file ) SetWriteDeadline (deadline  time.Time ) error  {
273236	return  f .writeDeadline .set (deadline )
274237}
275238
276- func  (f  * win32File ) Flush () error  {
239+ func  (f  * file ) Flush () error  {
277240	return  windows .FlushFileBuffers (f .handle )
278241}
279242
280- func  (f  * win32File ) Fd () uintptr  {
243+ func  (f  * file ) Fd () uintptr  {
281244	return  uintptr (f .handle )
282245}
283246
@@ -291,7 +254,7 @@ func (d *deadlineHandler) set(deadline time.Time) error {
291254		}
292255		d .timer  =  nil 
293256	}
294- 	d .timedout . setFalse ( )
257+ 	atomic . StoreUint32 ( & d .timedout ,  0 )
295258
296259	select  {
297260	case  <- d .channel :
@@ -306,7 +269,7 @@ func (d *deadlineHandler) set(deadline time.Time) error {
306269	}
307270
308271	timeoutIO  :=  func () {
309- 		d .timedout . setTrue ( )
272+ 		atomic . StoreUint32 ( & d .timedout ,  1 )
310273		close (d .channel )
311274	}
312275
0 commit comments