Introduce .gitattributes file for patches of libgit2
[TortoiseGit.git] / src / TortoisePlink / Windows / WINHANDL.C
blob11a0de482611800e15f07d28375c0667cbc1a104
1 /*\r
2  * winhandl.c: Module to give Windows front ends the general\r
3  * ability to deal with consoles, pipes, serial ports, or any other\r
4  * type of data stream accessed through a Windows API HANDLE rather\r
5  * than a WinSock SOCKET.\r
6  *\r
7  * We do this by spawning a subthread to continuously try to read\r
8  * from the handle. Every time a read successfully returns some\r
9  * data, the subthread sets an event object which is picked up by\r
10  * the main thread, and the main thread then sets an event in\r
11  * return to instruct the subthread to resume reading.\r
12  * \r
13  * Output works precisely the other way round, in a second\r
14  * subthread. The output subthread should not be attempting to\r
15  * write all the time, because it hasn't always got data _to_\r
16  * write; so the output thread waits for an event object notifying\r
17  * it to _attempt_ a write, and then it sets an event in return\r
18  * when one completes.\r
19  * \r
20  * (It's terribly annoying having to spawn a subthread for each\r
21  * direction of each handle. Technically it isn't necessary for\r
22  * serial ports, since we could use overlapped I/O within the main\r
23  * thread and wait directly on the event objects in the OVERLAPPED\r
24  * structures. However, we can't use this trick for some types of\r
25  * file handle at all - for some reason Windows restricts use of\r
26  * OVERLAPPED to files which were opened with the overlapped flag -\r
27  * and so we must use threads for those. This being the case, it's\r
28  * simplest just to use threads for everything rather than trying\r
29  * to keep track of multiple completely separate mechanisms.)\r
30  */\r
32 #include <assert.h>\r
34 #include "putty.h"\r
36 /* ----------------------------------------------------------------------\r
37  * Generic definitions.\r
38  */\r
40 /*\r
41  * Maximum amount of backlog we will allow to build up on an input\r
42  * handle before we stop reading from it.\r
43  */\r
44 #define MAX_BACKLOG 32768\r
46 struct handle_generic {\r
47     /*\r
48      * Initial fields common to both handle_input and handle_output\r
49      * structures.\r
50      * \r
51      * The three HANDLEs are set up at initialisation time and are\r
52      * thereafter read-only to both main thread and subthread.\r
53      * `moribund' is only used by the main thread; `done' is\r
54      * written by the main thread before signalling to the\r
55      * subthread. `defunct' and `busy' are used only by the main\r
56      * thread.\r
57      */\r
58     HANDLE h;                          /* the handle itself */\r
59     HANDLE ev_to_main;                 /* event used to signal main thread */\r
60     HANDLE ev_from_main;               /* event used to signal back to us */\r
61     int moribund;                      /* are we going to kill this soon? */\r
62     int done;                          /* request subthread to terminate */\r
63     int defunct;                       /* has the subthread already gone? */\r
64     int busy;                          /* operation currently in progress? */\r
65     void *privdata;                    /* for client to remember who they are */\r
66 };\r
68 typedef enum { HT_INPUT, HT_OUTPUT, HT_FOREIGN } HandleType;\r
70 /* ----------------------------------------------------------------------\r
71  * Input threads.\r
72  */\r
74 /*\r
75  * Data required by an input thread.\r
76  */\r
77 struct handle_input {\r
78     /*\r
79      * Copy of the handle_generic structure.\r
80      */\r
81     HANDLE h;                          /* the handle itself */\r
82     HANDLE ev_to_main;                 /* event used to signal main thread */\r
83     HANDLE ev_from_main;               /* event used to signal back to us */\r
84     int moribund;                      /* are we going to kill this soon? */\r
85     int done;                          /* request subthread to terminate */\r
86     int defunct;                       /* has the subthread already gone? */\r
87     int busy;                          /* operation currently in progress? */\r
88     void *privdata;                    /* for client to remember who they are */\r
90     /*\r
91      * Data set at initialisation and then read-only.\r
92      */\r
93     int flags;\r
95     /*\r
96      * Data set by the input thread before signalling ev_to_main,\r
97      * and read by the main thread after receiving that signal.\r
98      */\r
99     char buffer[4096];                 /* the data read from the handle */\r
100     DWORD len;                         /* how much data that was */\r
101     int readerr;                       /* lets us know about read errors */\r
103     /*\r
104      * Callback function called by this module when data arrives on\r
105      * an input handle.\r
106      */\r
107     handle_inputfn_t gotdata;\r
108 };\r
110 /*\r
111  * The actual thread procedure for an input thread.\r
112  */\r
113 static DWORD WINAPI handle_input_threadfunc(void *param)\r
115     struct handle_input *ctx = (struct handle_input *) param;\r
116     OVERLAPPED ovl, *povl;\r
117     HANDLE oev;\r
118     int readret, readlen;\r
120     if (ctx->flags & HANDLE_FLAG_OVERLAPPED) {\r
121         povl = &ovl;\r
122         oev = CreateEvent(NULL, TRUE, FALSE, NULL);\r
123     } else {\r
124         povl = NULL;\r
125     }\r
127     if (ctx->flags & HANDLE_FLAG_UNITBUFFER)\r
128         readlen = 1;\r
129     else\r
130         readlen = sizeof(ctx->buffer);\r
132     while (1) {\r
133         if (povl) {\r
134             memset(povl, 0, sizeof(OVERLAPPED));\r
135             povl->hEvent = oev;\r
136         }\r
137         readret = ReadFile(ctx->h, ctx->buffer,readlen, &ctx->len, povl);\r
138         if (!readret)\r
139             ctx->readerr = GetLastError();\r
140         else\r
141             ctx->readerr = 0;\r
142         if (povl && !readret && ctx->readerr == ERROR_IO_PENDING) {\r
143             WaitForSingleObject(povl->hEvent, INFINITE);\r
144             readret = GetOverlappedResult(ctx->h, povl, &ctx->len, FALSE);\r
145             if (!readret)\r
146                 ctx->readerr = GetLastError();\r
147             else\r
148                 ctx->readerr = 0;\r
149         }\r
151         if (!readret) {\r
152             /*\r
153              * Windows apparently sends ERROR_BROKEN_PIPE when a\r
154              * pipe we're reading from is closed normally from the\r
155              * writing end. This is ludicrous; if that situation\r
156              * isn't a natural EOF, _nothing_ is. So if we get that\r
157              * particular error, we pretend it's EOF.\r
158              */\r
159             if (ctx->readerr == ERROR_BROKEN_PIPE)\r
160                 ctx->readerr = 0;\r
161             ctx->len = 0;\r
162         }\r
164         if (readret && ctx->len == 0 &&\r
165             (ctx->flags & HANDLE_FLAG_IGNOREEOF))\r
166             continue;\r
168         SetEvent(ctx->ev_to_main);\r
170         if (!ctx->len)\r
171             break;\r
173         WaitForSingleObject(ctx->ev_from_main, INFINITE);\r
174         if (ctx->done) {\r
175             SetEvent(ctx->ev_to_main);\r
176             break;                     /* main thread told us to shut down */\r
177         }\r
178     }\r
180     if (povl)\r
181         CloseHandle(oev);\r
183     return 0;\r
186 /*\r
187  * This is called after a succcessful read, or from the\r
188  * `unthrottle' function. It decides whether or not to begin a new\r
189  * read operation.\r
190  */\r
191 static void handle_throttle(struct handle_input *ctx, int backlog)\r
193     if (ctx->defunct)\r
194         return;\r
196     /*\r
197      * If there's a read operation already in progress, do nothing:\r
198      * when that completes, we'll come back here and be in a\r
199      * position to make a better decision.\r
200      */\r
201     if (ctx->busy)\r
202         return;\r
204     /*\r
205      * Otherwise, we must decide whether to start a new read based\r
206      * on the size of the backlog.\r
207      */\r
208     if (backlog < MAX_BACKLOG) {\r
209         SetEvent(ctx->ev_from_main);\r
210         ctx->busy = TRUE;\r
211     }\r
214 /* ----------------------------------------------------------------------\r
215  * Output threads.\r
216  */\r
218 /*\r
219  * Data required by an output thread.\r
220  */\r
221 struct handle_output {\r
222     /*\r
223      * Copy of the handle_generic structure.\r
224      */\r
225     HANDLE h;                          /* the handle itself */\r
226     HANDLE ev_to_main;                 /* event used to signal main thread */\r
227     HANDLE ev_from_main;               /* event used to signal back to us */\r
228     int moribund;                      /* are we going to kill this soon? */\r
229     int done;                          /* request subthread to terminate */\r
230     int defunct;                       /* has the subthread already gone? */\r
231     int busy;                          /* operation currently in progress? */\r
232     void *privdata;                    /* for client to remember who they are */\r
234     /*\r
235      * Data set at initialisation and then read-only.\r
236      */\r
237     int flags;\r
239     /*\r
240      * Data set by the main thread before signalling ev_from_main,\r
241      * and read by the input thread after receiving that signal.\r
242      */\r
243     char *buffer;                      /* the data to write */\r
244     DWORD len;                         /* how much data there is */\r
246     /*\r
247      * Data set by the input thread before signalling ev_to_main,\r
248      * and read by the main thread after receiving that signal.\r
249      */\r
250     DWORD lenwritten;                  /* how much data we actually wrote */\r
251     int writeerr;                      /* return value from WriteFile */\r
253     /*\r
254      * Data only ever read or written by the main thread.\r
255      */\r
256     bufchain queued_data;              /* data still waiting to be written */\r
257     enum { EOF_NO, EOF_PENDING, EOF_SENT } outgoingeof;\r
259     /*\r
260      * Callback function called when the backlog in the bufchain\r
261      * drops.\r
262      */\r
263     handle_outputfn_t sentdata;\r
264 };\r
266 static DWORD WINAPI handle_output_threadfunc(void *param)\r
268     struct handle_output *ctx = (struct handle_output *) param;\r
269     OVERLAPPED ovl, *povl;\r
270     HANDLE oev;\r
271     int writeret;\r
273     if (ctx->flags & HANDLE_FLAG_OVERLAPPED) {\r
274         povl = &ovl;\r
275         oev = CreateEvent(NULL, TRUE, FALSE, NULL);\r
276     } else {\r
277         povl = NULL;\r
278     }\r
280     while (1) {\r
281         WaitForSingleObject(ctx->ev_from_main, INFINITE);\r
282         if (ctx->done) {\r
283             SetEvent(ctx->ev_to_main);\r
284             break;\r
285         }\r
286         if (povl) {\r
287             memset(povl, 0, sizeof(OVERLAPPED));\r
288             povl->hEvent = oev;\r
289         }\r
291         writeret = WriteFile(ctx->h, ctx->buffer, ctx->len,\r
292                              &ctx->lenwritten, povl);\r
293         if (!writeret)\r
294             ctx->writeerr = GetLastError();\r
295         else\r
296             ctx->writeerr = 0;\r
297         if (povl && !writeret && GetLastError() == ERROR_IO_PENDING) {\r
298             writeret = GetOverlappedResult(ctx->h, povl,\r
299                                            &ctx->lenwritten, TRUE);\r
300             if (!writeret)\r
301                 ctx->writeerr = GetLastError();\r
302             else\r
303                 ctx->writeerr = 0;\r
304         }\r
306         SetEvent(ctx->ev_to_main);\r
307         if (!writeret)\r
308             break;\r
309     }\r
311     if (povl)\r
312         CloseHandle(oev);\r
314     return 0;\r
317 static void handle_try_output(struct handle_output *ctx)\r
319     void *senddata;\r
320     int sendlen;\r
322     if (!ctx->busy && bufchain_size(&ctx->queued_data)) {\r
323         bufchain_prefix(&ctx->queued_data, &senddata, &sendlen);\r
324         ctx->buffer = senddata;\r
325         ctx->len = sendlen;\r
326         SetEvent(ctx->ev_from_main);\r
327         ctx->busy = TRUE;\r
328     } else if (!ctx->busy && bufchain_size(&ctx->queued_data) == 0 &&\r
329                ctx->outgoingeof == EOF_PENDING) {\r
330         CloseHandle(ctx->h);\r
331         ctx->h = INVALID_HANDLE_VALUE;\r
332         ctx->outgoingeof = EOF_SENT;\r
333     }\r
336 /* ----------------------------------------------------------------------\r
337  * 'Foreign events'. These are handle structures which just contain a\r
338  * single event object passed to us by another module such as\r
339  * winnps.c, so that they can make use of our handle_get_events /\r
340  * handle_got_event mechanism for communicating with application main\r
341  * loops.\r
342  */\r
343 struct handle_foreign {\r
344     /*\r
345      * Copy of the handle_generic structure.\r
346      */\r
347     HANDLE h;                          /* the handle itself */\r
348     HANDLE ev_to_main;                 /* event used to signal main thread */\r
349     HANDLE ev_from_main;               /* event used to signal back to us */\r
350     int moribund;                      /* are we going to kill this soon? */\r
351     int done;                          /* request subthread to terminate */\r
352     int defunct;                       /* has the subthread already gone? */\r
353     int busy;                          /* operation currently in progress? */\r
354     void *privdata;                    /* for client to remember who they are */\r
356     /*\r
357      * Our own data, just consisting of knowledge of who to call back.\r
358      */\r
359     void (*callback)(void *);\r
360     void *ctx;\r
361 };\r
363 /* ----------------------------------------------------------------------\r
364  * Unified code handling both input and output threads.\r
365  */\r
367 struct handle {\r
368     HandleType type;\r
369     union {\r
370         struct handle_generic g;\r
371         struct handle_input i;\r
372         struct handle_output o;\r
373         struct handle_foreign f;\r
374     } u;\r
375 };\r
377 static tree234 *handles_by_evtomain;\r
379 static int handle_cmp_evtomain(void *av, void *bv)\r
381     struct handle *a = (struct handle *)av;\r
382     struct handle *b = (struct handle *)bv;\r
384     if ((unsigned)a->u.g.ev_to_main < (unsigned)b->u.g.ev_to_main)\r
385         return -1;\r
386     else if ((unsigned)a->u.g.ev_to_main > (unsigned)b->u.g.ev_to_main)\r
387         return +1;\r
388     else\r
389         return 0;\r
392 static int handle_find_evtomain(void *av, void *bv)\r
394     HANDLE *a = (HANDLE *)av;\r
395     struct handle *b = (struct handle *)bv;\r
397     if ((unsigned)*a < (unsigned)b->u.g.ev_to_main)\r
398         return -1;\r
399     else if ((unsigned)*a > (unsigned)b->u.g.ev_to_main)\r
400         return +1;\r
401     else\r
402         return 0;\r
405 struct handle *handle_input_new(HANDLE handle, handle_inputfn_t gotdata,\r
406                                 void *privdata, int flags)\r
408     struct handle *h = snew(struct handle);\r
409     DWORD in_threadid; /* required for Win9x */\r
411     h->type = HT_INPUT;\r
412     h->u.i.h = handle;\r
413     h->u.i.ev_to_main = CreateEvent(NULL, FALSE, FALSE, NULL);\r
414     h->u.i.ev_from_main = CreateEvent(NULL, FALSE, FALSE, NULL);\r
415     h->u.i.gotdata = gotdata;\r
416     h->u.i.defunct = FALSE;\r
417     h->u.i.moribund = FALSE;\r
418     h->u.i.done = FALSE;\r
419     h->u.i.privdata = privdata;\r
420     h->u.i.flags = flags;\r
422     if (!handles_by_evtomain)\r
423         handles_by_evtomain = newtree234(handle_cmp_evtomain);\r
424     add234(handles_by_evtomain, h);\r
426     CreateThread(NULL, 0, handle_input_threadfunc,\r
427                  &h->u.i, 0, &in_threadid);\r
428     h->u.i.busy = TRUE;\r
430     return h;\r
433 struct handle *handle_output_new(HANDLE handle, handle_outputfn_t sentdata,\r
434                                  void *privdata, int flags)\r
436     struct handle *h = snew(struct handle);\r
437     DWORD out_threadid; /* required for Win9x */\r
439     h->type = HT_OUTPUT;\r
440     h->u.o.h = handle;\r
441     h->u.o.ev_to_main = CreateEvent(NULL, FALSE, FALSE, NULL);\r
442     h->u.o.ev_from_main = CreateEvent(NULL, FALSE, FALSE, NULL);\r
443     h->u.o.busy = FALSE;\r
444     h->u.o.defunct = FALSE;\r
445     h->u.o.moribund = FALSE;\r
446     h->u.o.done = FALSE;\r
447     h->u.o.privdata = privdata;\r
448     bufchain_init(&h->u.o.queued_data);\r
449     h->u.o.outgoingeof = EOF_NO;\r
450     h->u.o.sentdata = sentdata;\r
451     h->u.o.flags = flags;\r
453     if (!handles_by_evtomain)\r
454         handles_by_evtomain = newtree234(handle_cmp_evtomain);\r
455     add234(handles_by_evtomain, h);\r
457     CreateThread(NULL, 0, handle_output_threadfunc,\r
458                  &h->u.o, 0, &out_threadid);\r
460     return h;\r
463 struct handle *handle_add_foreign_event(HANDLE event,\r
464                                         void (*callback)(void *), void *ctx)\r
466     struct handle *h = snew(struct handle);\r
468     h->type = HT_FOREIGN;\r
469     h->u.f.h = INVALID_HANDLE_VALUE;\r
470     h->u.f.ev_to_main = event;\r
471     h->u.f.ev_from_main = INVALID_HANDLE_VALUE;\r
472     h->u.f.defunct = TRUE;  /* we have no thread in the first place */\r
473     h->u.f.moribund = FALSE;\r
474     h->u.f.done = FALSE;\r
475     h->u.f.privdata = NULL;\r
476     h->u.f.callback = callback;\r
477     h->u.f.ctx = ctx;\r
478     h->u.f.busy = TRUE;\r
480     if (!handles_by_evtomain)\r
481         handles_by_evtomain = newtree234(handle_cmp_evtomain);\r
482     add234(handles_by_evtomain, h);\r
484     return h;\r
487 int handle_write(struct handle *h, const void *data, int len)\r
489     assert(h->type == HT_OUTPUT);\r
490     assert(h->u.o.outgoingeof == EOF_NO);\r
491     bufchain_add(&h->u.o.queued_data, data, len);\r
492     handle_try_output(&h->u.o);\r
493     return bufchain_size(&h->u.o.queued_data);\r
496 void handle_write_eof(struct handle *h)\r
498     /*\r
499      * This function is called when we want to proactively send an\r
500      * end-of-file notification on the handle. We can only do this by\r
501      * actually closing the handle - so never call this on a\r
502      * bidirectional handle if we're still interested in its incoming\r
503      * direction!\r
504      */\r
505     assert(h->type == HT_OUTPUT);\r
506     if (!h->u.o.outgoingeof == EOF_NO) {\r
507         h->u.o.outgoingeof = EOF_PENDING;\r
508         handle_try_output(&h->u.o);\r
509     }\r
512 HANDLE *handle_get_events(int *nevents)\r
514     HANDLE *ret;\r
515     struct handle *h;\r
516     int i, n, size;\r
518     /*\r
519      * Go through our tree counting the handle objects currently\r
520      * engaged in useful activity.\r
521      */\r
522     ret = NULL;\r
523     n = size = 0;\r
524     if (handles_by_evtomain) {\r
525         for (i = 0; (h = index234(handles_by_evtomain, i)) != NULL; i++) {\r
526             if (h->u.g.busy) {\r
527                 if (n >= size) {\r
528                     size += 32;\r
529                     ret = sresize(ret, size, HANDLE);\r
530                 }\r
531                 ret[n++] = h->u.g.ev_to_main;\r
532             }\r
533         }\r
534     }\r
536     *nevents = n;\r
537     return ret;\r
540 static void handle_destroy(struct handle *h)\r
542     if (h->type == HT_OUTPUT)\r
543         bufchain_clear(&h->u.o.queued_data);\r
544     CloseHandle(h->u.g.ev_from_main);\r
545     CloseHandle(h->u.g.ev_to_main);\r
546     del234(handles_by_evtomain, h);\r
547     sfree(h);\r
550 void handle_free(struct handle *h)\r
552     /*\r
553      * If the handle is currently busy, we cannot immediately free\r
554      * it. Instead we must wait until it's finished its current\r
555      * operation, because otherwise the subthread will write to\r
556      * invalid memory after we free its context from under it.\r
557      */\r
558     assert(h && !h->u.g.moribund);\r
559     if (h->u.g.busy) {\r
560         /*\r
561          * Just set the moribund flag, which will be noticed next\r
562          * time an operation completes.\r
563          */\r
564         h->u.g.moribund = TRUE;\r
565     } else if (h->u.g.defunct) {\r
566         /*\r
567          * There isn't even a subthread; we can go straight to\r
568          * handle_destroy.\r
569          */\r
570         handle_destroy(h);\r
571     } else {\r
572         /*\r
573          * The subthread is alive but not busy, so we now signal it\r
574          * to die. Set the moribund flag to indicate that it will\r
575          * want destroying after that.\r
576          */\r
577         h->u.g.moribund = TRUE;\r
578         h->u.g.done = TRUE;\r
579         h->u.g.busy = TRUE;\r
580         SetEvent(h->u.g.ev_from_main);\r
581     }\r
584 void handle_got_event(HANDLE event)\r
586     struct handle *h;\r
588     assert(handles_by_evtomain);\r
589     h = find234(handles_by_evtomain, &event, handle_find_evtomain);\r
590     if (!h) {\r
591         /*\r
592          * This isn't an error condition. If two or more event\r
593          * objects were signalled during the same select operation,\r
594          * and processing of the first caused the second handle to\r
595          * be closed, then it will sometimes happen that we receive\r
596          * an event notification here for a handle which is already\r
597          * deceased. In that situation we simply do nothing.\r
598          */\r
599         return;\r
600     }\r
602     if (h->u.g.moribund) {\r
603         /*\r
604          * A moribund handle is already treated as dead from the\r
605          * external user's point of view, so do nothing with the\r
606          * actual event. Just signal the thread to die if\r
607          * necessary, or destroy the handle if not.\r
608          */\r
609         if (h->u.g.done) {\r
610             handle_destroy(h);\r
611         } else {\r
612             h->u.g.done = TRUE;\r
613             h->u.g.busy = TRUE;\r
614             SetEvent(h->u.g.ev_from_main);\r
615         }\r
616         return;\r
617     }\r
619     switch (h->type) {\r
620         int backlog;\r
622       case HT_INPUT:\r
623         h->u.i.busy = FALSE;\r
625         /*\r
626          * A signal on an input handle means data has arrived.\r
627          */\r
628         if (h->u.i.len == 0) {\r
629             /*\r
630              * EOF, or (nearly equivalently) read error.\r
631              */\r
632             h->u.i.defunct = TRUE;\r
633             h->u.i.gotdata(h, NULL, -h->u.i.readerr);\r
634         } else {\r
635             backlog = h->u.i.gotdata(h, h->u.i.buffer, h->u.i.len);\r
636             handle_throttle(&h->u.i, backlog);\r
637         }\r
638         break;\r
640       case HT_OUTPUT:\r
641         h->u.o.busy = FALSE;\r
643         /*\r
644          * A signal on an output handle means we have completed a\r
645          * write. Call the callback to indicate that the output\r
646          * buffer size has decreased, or to indicate an error.\r
647          */\r
648         if (h->u.o.writeerr) {\r
649             /*\r
650              * Write error. Send a negative value to the callback,\r
651              * and mark the thread as defunct (because the output\r
652              * thread is terminating by now).\r
653              */\r
654             h->u.o.defunct = TRUE;\r
655             h->u.o.sentdata(h, -h->u.o.writeerr);\r
656         } else {\r
657             bufchain_consume(&h->u.o.queued_data, h->u.o.lenwritten);\r
658             h->u.o.sentdata(h, bufchain_size(&h->u.o.queued_data));\r
659             handle_try_output(&h->u.o);\r
660         }\r
661         break;\r
663       case HT_FOREIGN:\r
664         /* Just call the callback. */\r
665         h->u.f.callback(h->u.f.ctx);\r
666         break;\r
667     }\r
670 void handle_unthrottle(struct handle *h, int backlog)\r
672     assert(h->type == HT_INPUT);\r
673     handle_throttle(&h->u.i, backlog);\r
676 int handle_backlog(struct handle *h)\r
678     assert(h->type == HT_OUTPUT);\r
679     return bufchain_size(&h->u.o.queued_data);\r
682 void *handle_get_privdata(struct handle *h)\r
684     return h->u.g.privdata;\r