2005-12-31 Marcus Brinkmann <marcus@g10code.de>
[gpg4win.git] / patches / glib-2.6.6 / 01-giowin32.patch
1 #! /bin/sh
2 patch -p1 -f $* < $0
3 exit $?
4
5 Implement write support for fd I/O channels in glib on W32 targets.
6
7 (no changelog yet)
8
9 diff -ru glib/giowin32.c glib-2.6.6/glib/giowin32.c
10 --- glib/giowin32.c     2005-03-30 14:02:48.000000000 +0200
11 +++ glib/giowin32.c     2005-12-31 04:37:17.000000000 +0100
12 @@ -95,7 +95,8 @@
13    gushort revents;
14  
15    /* Following fields used by fd channels for input */
16 -  
17 +  int direction;
18 +
19    /* Data is kept in a circular buffer. To be able to distinguish between
20     * empty and full buffer, we cannot fill it completely, but have to
21     * leave a one character gap.
22 @@ -215,6 +216,7 @@
23      }
24  }
25  
26 +
27  static unsigned __stdcall
28  read_thread (void *parameter)
29  {
30 @@ -231,6 +233,7 @@
31              (guint) channel->data_avail_event,
32              (guint) channel->space_avail_event);
33    
34 +  channel->direction = 0;
35    channel->buffer = g_malloc (BUFFER_SIZE);
36    channel->rdp = channel->wrp = 0;
37    channel->running = TRUE;
38 @@ -276,7 +279,12 @@
39        UNLOCK (channel->mutex);
40  
41        nbytes = read (channel->fd, buffer, nbytes);
42 -      
43 +      //      {
44 +      //       DWORD nb;
45 +      //       ReadFile (_get_osfhandle (channel->fd), buffer, nbytes, &nb, NULL);
46 +      //       nbytes = nb;
47 +      //      }
48 +
49        LOCK (channel->mutex);
50  
51        channel->revents = G_IO_IN;
52 @@ -325,6 +333,121 @@
53    return 0;
54  }
55  
56 +
57 +static unsigned __stdcall
58 +write_thread (void *parameter)
59 +{
60 +  GIOWin32Channel *channel = parameter;
61 +  guchar *buffer;
62 +  guint nbytes;
63 +
64 +  g_io_channel_ref ((GIOChannel *)channel);
65 +
66 +  if (channel->debug)
67 +    g_print ("write_thread %#x: start fd:%d, data_avail:%#x space_avail:%#x\n",
68 +            channel->thread_id,
69 +            channel->fd,
70 +            (guint) channel->data_avail_event,
71 +            (guint) channel->space_avail_event);
72 +  
73 +  channel->direction = 1;
74 +  channel->buffer = g_malloc (BUFFER_SIZE);
75 +  channel->rdp = channel->wrp = 0;
76 +  channel->running = TRUE;
77 +
78 +  SetEvent (channel->space_avail_event);
79 +  
80 +  LOCK (channel->mutex);
81 +  while (channel->running)
82 +    {
83 +      if (channel->debug)
84 +       g_print ("write_thread %#x: rdp=%d, wrp=%d\n",
85 +                channel->thread_id, channel->rdp, channel->wrp);
86 +      if (channel->wrp == channel->rdp)
87 +       {
88 +         /* Buffer is empty.  */
89 +         if (channel->debug)
90 +           g_print ("write_thread %#x: resetting space_avail\n",
91 +                    channel->thread_id);
92 +         ResetEvent (channel->space_avail_event);
93 +         if (channel->debug)
94 +           g_print ("write_thread %#x: waiting for data\n",
95 +                    channel->thread_id);
96 +         channel->revents = G_IO_OUT;
97 +         SetEvent (channel->data_avail_event);
98 +         UNLOCK (channel->mutex);
99 +         WaitForSingleObject (channel->space_avail_event, INFINITE);
100 +
101 +         LOCK (channel->mutex);
102 +         if (channel->debug)
103 +           g_print ("write_thread %#x: rdp=%d, wrp=%d\n",
104 +                    channel->thread_id, channel->rdp, channel->wrp);
105 +       }
106 +      
107 +      buffer = channel->buffer + channel->rdp;
108 +      if (channel->rdp < channel->wrp)
109 +       nbytes = channel->wrp - channel->rdp;
110 +      else
111 +       nbytes = BUFFER_SIZE - channel->rdp;
112 +
113 +      if (channel->debug)
114 +       g_print ("write_thread %#x: calling write() for %d bytes\n",
115 +                channel->thread_id, nbytes);
116 +
117 +      UNLOCK (channel->mutex);
118 +      nbytes = write (channel->fd, buffer, nbytes);
119 +      //      {
120 +      //       DWORD nb;
121 +      //       WriteFile (_get_osfhandle (channel->fd), buffer, nbytes, &nb, NULL);
122 +      //       nbytes = nb;
123 +      //      }
124 +
125 +      LOCK (channel->mutex);
126 +
127 +      if (channel->debug)
128 +       g_print ("write_thread %#x: write(%i) returned %d, rdp=%d, wrp=%d\n",
129 +                channel->thread_id, channel->fd, nbytes, channel->rdp, channel->wrp);
130 +
131 +      channel->revents = 0;
132 +      if (nbytes > 0)
133 +       channel->revents |= G_IO_OUT;
134 +      else if (nbytes <= 0)
135 +       channel->revents |= G_IO_ERR;
136 +
137 +      channel->rdp = (channel->rdp + nbytes) % BUFFER_SIZE;
138 +
139 +      if (nbytes <= 0)
140 +       break;
141 +
142 +      if (channel->debug)
143 +       g_print ("write_thread: setting data_avail for thread %#x\n",
144 +                channel->thread_id);
145 +      SetEvent (channel->data_avail_event);
146 +    }
147 +  
148 +  channel->running = FALSE;
149 +  if (channel->needs_close)
150 +    {
151 +      if (channel->debug)
152 +       g_print ("write_thread %#x: channel fd %d needs closing\n",
153 +                channel->thread_id, channel->fd);
154 +      close (channel->fd);
155 +      channel->fd = -1;
156 +    }
157 +
158 +  UNLOCK (channel->mutex);
159 +  
160 +  g_io_channel_unref ((GIOChannel *)channel);
161 +  
162 +  /* No need to call _endthreadex(), the actual thread starter routine
163 +   * in MSVCRT (see crt/src/threadex.c:_threadstartex) calls
164 +   * _endthreadex() for us.
165 +   */
166 +
167 +  return 0;
168 +}
169 +
170 +
171  static void
172  create_thread (GIOWin32Channel     *channel,
173                GIOCondition         condition,
174 @@ -341,6 +464,8 @@
175      g_warning (G_STRLOC ": Error closing thread handle: %s\n",
176                g_win32_error_message (GetLastError ()));
177  
178 +  SetThreadPriority (thread_handle, THREAD_PRIORITY_HIGHEST);
179 +
180    WaitForSingleObject (channel->space_avail_event, INFINITE);
181  }
182  
183 @@ -474,6 +599,80 @@
184    return (*bytes_read > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
185  }
186  
187 +
188 +static GIOStatus
189 +buffer_write (GIOWin32Channel *channel,
190 +             const guchar    *dest,
191 +             gsize            count,
192 +             gsize           *bytes_written,
193 +             GError         **err)
194 +{
195 +  guint nbytes;
196 +  guint left = count;
197 +  
198 +  LOCK (channel->mutex);
199 +  if (channel->debug)
200 +    g_print ("buffer_write: writing to thread %#x %d bytes, rdp=%d, wrp=%d\n",
201 +            channel->thread_id, count, channel->rdp, channel->wrp);
202 +  
203 +  if ((channel->wrp + 1) % BUFFER_SIZE == channel->rdp)
204 +    {
205 +      /* Buffer is full */
206 +      if (channel->debug)
207 +       g_print ("buffer_write: tid %#x: resetting data_avail\n",
208 +                channel->thread_id);
209 +      ResetEvent (channel->data_avail_event);
210 +      if (channel->debug)
211 +       g_print ("buffer_write: tid %#x: waiting for space\n",
212 +                channel->thread_id);
213 +      UNLOCK (channel->mutex);
214 +      WaitForSingleObject (channel->data_avail_event, INFINITE);
215 +      LOCK (channel->mutex);
216 +      if (channel->debug)
217 +       g_print ("buffer_write: tid %#x: rdp=%d, wrp=%d\n",
218 +                channel->thread_id, channel->rdp, channel->wrp);
219 +    }
220 +   
221 +
222 +  /* Always leave at least one byte unused gap to be able to
223 +     distinguish between the full and empty condition.  */
224 +  nbytes = MIN ((channel->rdp + BUFFER_SIZE - channel->wrp - 1) % BUFFER_SIZE,
225 +               BUFFER_SIZE - channel->wrp);
226 +
227 +  UNLOCK (channel->mutex);
228 +  nbytes = MIN (left, nbytes);
229 +  if (channel->debug)
230 +    g_print ("buffer_write: tid %#x: writing %d bytes\n",
231 +            channel->thread_id, nbytes);
232 +  memcpy (channel->buffer + channel->wrp, dest, nbytes);
233 +  dest += nbytes;
234 +  left -= nbytes;
235 +  LOCK (channel->mutex);
236 +
237 +  channel->wrp = (channel->wrp + nbytes) % BUFFER_SIZE;
238 +  if (channel->debug)
239 +    g_print ("buffer_write: tid %#x: rdp=%d, wrp=%d, setting space_avail\n",
240 +            channel->thread_id, channel->rdp, channel->wrp);
241 +  SetEvent (channel->space_avail_event);
242 +
243 +  if ((channel->wrp + 1) % BUFFER_SIZE == channel->rdp)
244 +    {
245 +      /* Buffer is full */
246 +      if (channel->debug)
247 +       g_print ("buffer_write: tid %#x: resetting data_avail\n",
248 +                channel->thread_id);
249 +      ResetEvent (channel->data_avail_event);
250 +    }
251 +
252 +  UNLOCK (channel->mutex);
253 +  
254 +  /* We have no way to indicate any errors form the actual
255 +     write() call in the writer thread. Should we have?  */
256 +  *bytes_written = count - left;
257 +  return (*bytes_written > 0) ? G_IO_STATUS_NORMAL : G_IO_STATUS_EOF;
258 +}
259 +
260 +
261  static unsigned __stdcall
262  select_thread (void *parameter)
263  {
264 @@ -629,13 +828,27 @@
265    if (channel->type == G_IO_WIN32_FILE_DESC)
266      {
267        LOCK (channel->mutex);
268 -      if (channel->running && channel->wrp == channel->rdp)
269 +      if (channel->running)
270         {
271 -         if (channel->debug)
272 -           g_print ("g_io_win32_prepare: for thread %#x, setting channel->revents = 0\n",
273 -                    channel->thread_id);
274 -         channel->revents = 0;
275 +         if (channel->direction == 0 && channel->wrp == channel->rdp)
276 +           {
277 +             if (channel->debug)
278 +               g_print ("g_io_win32_prepare: for thread %#x, setting channel->revents = 0\n",
279 +                        channel->thread_id);
280 +             channel->revents = 0;
281 +           }
282         }
283 +      else
284 +       {
285 +         if (channel->direction == 1
286 +             && (channel->wrp + 1) % BUFFER_SIZE == channel->rdp)
287 +           {
288 +             if (channel->debug)
289 +               g_print ("g_io_win32_prepare: for thread %#x, setting channel->revents = %i\n",
290 +                        channel->thread_id, 0);
291 +             channel->revents = 0;
292 +           }
293 +       }         
294        UNLOCK (channel->mutex);
295      }
296    else if (channel->type == G_IO_WIN32_SOCKET)
297 @@ -968,6 +1181,12 @@
298    GIOWin32Channel *win32_channel = (GIOWin32Channel *)channel;
299    gint result;
300    
301 +  if (win32_channel->thread_id)
302 +    {
303 +      return buffer_write (win32_channel, buf, count, bytes_written, err);
304 +    }
305 +
306 +
307    result = write (win32_channel->fd, buf, count);
308    if (win32_channel->debug)
309      g_print ("g_io_win32_fd_write: fd:%d count:%d = %d\n",
310 @@ -1086,7 +1305,9 @@
311  g_io_win32_fd_create_watch (GIOChannel    *channel,
312                             GIOCondition   condition)
313  {
314 -  return g_io_win32_create_watch (channel, condition, read_thread);
315 +  return g_io_win32_create_watch (channel, condition,
316 +                                 (condition & G_IO_IN)
317 +                                 ? read_thread : write_thread);
318  }
319  
320  static GIOStatus
321 @@ -1701,8 +1922,13 @@
322  
323    if (win32_channel->thread_id == 0)
324      {
325 -      if ((condition & G_IO_IN) && win32_channel->type == G_IO_WIN32_FILE_DESC)
326 -       create_thread (win32_channel, condition, read_thread);
327 +      if (win32_channel->type == G_IO_WIN32_FILE_DESC)
328 +       {
329 +         if (condition & G_IO_IN)
330 +           create_thread (win32_channel, condition, read_thread);
331 +         else if (condition & G_IO_OUT)
332 +           create_thread (win32_channel, condition, write_thread);
333 +       }
334        else if (win32_channel->type == G_IO_WIN32_SOCKET)
335         create_thread (win32_channel, condition, select_thread);
336      }