3 /* Copyright (c) 1994-2012 by Marc Feeley, All Rights Reserved. */
6 * This module implements the operating system specific routines
10 #define ___INCLUDED_FROM_OS_IO
11 #define ___VERSION 406003
21 /*---------------------------------------------------------------------------*/
24 ___io_module ___io_mod
=
29 #ifdef ___IO_MODULE_INIT
35 /*---------------------------------------------------------------------------*/
40 ___SCMOBJ ___device_group_setup
41 ___P((___device_group
**dgroup
),
43 ___device_group
**dgroup
;)
48 g
= ___CAST(___device_group
*,
49 ___alloc_mem (sizeof (___device_group
)));
52 return ___FIX(___HEAP_OVERFLOW_ERR
);
58 return ___FIX(___NO_ERR
);
62 void ___device_group_cleanup
63 ___P((___device_group
*dgroup
),
65 ___device_group
*dgroup
;)
67 while (dgroup
->list
!= NULL
)
68 if (___device_cleanup (dgroup
->list
) != ___FIX(___NO_ERR
))
75 void ___device_add_to_group
76 ___P((___device_group
*dgroup
,
80 ___device_group
*dgroup
;
83 ___device
*head
= dgroup
->list
;
95 ___device
*tail
= head
->prev
;
103 void ___device_remove_from_group
104 ___P((___device
*dev
),
108 ___device_group
*dgroup
= dev
->group
;
109 ___device
*prev
= dev
->prev
;
110 ___device
*next
= dev
->next
;
116 if (dgroup
->list
== dev
)
127 ___device_group
*___global_device_group ___PVOID
129 return ___io_mod
.dgroup
;
133 /*---------------------------------------------------------------------------*/
135 /* Nonblocking pipes */
139 ___HIDDEN ___SCMOBJ ___nonblocking_pipe_setup
140 ___P((___nonblocking_pipe
*pipe
,
144 ___nonblocking_pipe
*pipe
;
152 buffer
= ___CAST(___U8
*,
153 ___alloc_mem (size
));
156 return ___FIX(___HEAP_OVERFLOW_ERR
);
158 mutex
= CreateMutex (NULL
, /* can't inherit */
159 FALSE
, /* unlocked */
164 ___SCMOBJ e
= err_code_from_GetLastError ();
165 ___free_mem (buffer
);
169 revent
= CreateEvent (NULL
, /* can't inherit */
170 TRUE
, /* manual reset */
171 FALSE
, /* not signaled */
176 ___SCMOBJ e
= err_code_from_GetLastError ();
177 CloseHandle (mutex
); /* ignore error */
178 ___free_mem (buffer
);
182 wevent
= CreateEvent (NULL
, /* can't inherit */
183 TRUE
, /* manual reset */
184 FALSE
, /* not signaled */
189 ___SCMOBJ e
= err_code_from_GetLastError ();
190 CloseHandle (revent
); /* ignore error */
191 CloseHandle (mutex
); /* ignore error */
192 ___free_mem (buffer
);
197 pipe
->revent
= revent
;
198 pipe
->wevent
= wevent
;
199 pipe
->rerr
= ___FIX(___NO_ERR
);
200 pipe
->werr
= ___FIX(___NO_ERR
);
205 pipe
->buffer
= buffer
;
207 return ___FIX(___NO_ERR
);
210 ___HIDDEN ___SCMOBJ ___nonblocking_pipe_cleanup
211 ___P((___nonblocking_pipe
*pipe
),
213 ___nonblocking_pipe
*pipe
;)
215 CloseHandle (pipe
->wevent
); /* ignore error */
216 CloseHandle (pipe
->revent
); /* ignore error */
217 CloseHandle (pipe
->mutex
); /* ignore error */
218 ___free_mem (pipe
->buffer
);
220 return ___FIX(___NO_ERR
);
223 ___HIDDEN ___SCMOBJ ___nonblocking_pipe_set_reader_err
224 ___P((___nonblocking_pipe
*pipe
,
228 ___nonblocking_pipe
*pipe
;
231 if (WaitForSingleObject (pipe
->mutex
, INFINITE
) == WAIT_FAILED
)
232 return err_code_from_GetLastError ();
234 /* note: the reader error indicator may get overwritten */
238 SetEvent (pipe
->wevent
); /* ignore error */
240 if (pipe
->werr
== ___FIX(___NO_ERR
))
241 ResetEvent (pipe
->revent
); /* ignore error */
243 ReleaseMutex (pipe
->mutex
); /* ignore error */
245 return ___FIX(___NO_ERR
);
248 ___HIDDEN ___SCMOBJ ___nonblocking_pipe_set_writer_err
249 ___P((___nonblocking_pipe
*pipe
,
253 ___nonblocking_pipe
*pipe
;
256 if (WaitForSingleObject (pipe
->mutex
, INFINITE
) == WAIT_FAILED
)
257 return err_code_from_GetLastError ();
259 /* note: the writer error indicator may get overwritten */
263 SetEvent (pipe
->revent
); /* ignore error */
265 if (pipe
->rerr
== ___FIX(___NO_ERR
))
266 ResetEvent (pipe
->wevent
); /* ignore error */
268 ReleaseMutex (pipe
->mutex
); /* ignore error */
270 return ___FIX(___NO_ERR
);
273 ___HIDDEN ___SCMOBJ ___nonblocking_pipe_write_oob
274 ___P((___nonblocking_pipe
*pipe
,
275 ___nonblocking_pipe_oob_msg
*oob_msg
),
278 ___nonblocking_pipe
*pipe
;
279 ___nonblocking_pipe_oob_msg
*oob_msg
;)
281 if (WaitForSingleObject (pipe
->mutex
, INFINITE
) == WAIT_FAILED
)
282 return err_code_from_GetLastError ();
284 if (pipe
->werr
!= ___FIX(___NO_ERR
) || pipe
->oob
)
286 ReleaseMutex (pipe
->mutex
); /* ignore error */
287 return ___ERR_CODE_EAGAIN
;
291 pipe
->oob_msg
= *oob_msg
;
293 if (pipe
->rerr
== ___FIX(___NO_ERR
))
295 SetEvent (pipe
->revent
); /* ignore error */
296 ResetEvent (pipe
->wevent
); /* ignore error */
299 ReleaseMutex (pipe
->mutex
); /* ignore error */
301 return ___FIX(___NO_ERR
);
304 ___HIDDEN ___SCMOBJ ___nonblocking_pipe_read_ready_wait
305 ___P((___nonblocking_pipe
*pipe
),
307 ___nonblocking_pipe
*pipe
;)
311 if (WaitForSingleObject (pipe
->revent
, INFINITE
) == WAIT_FAILED
||
312 WaitForSingleObject (pipe
->mutex
, INFINITE
) == WAIT_FAILED
)
313 return err_code_from_GetLastError ();
317 if (werr
!= ___FIX(___NO_ERR
))
319 pipe
->werr
= ___FIX(___NO_ERR
);
321 if (pipe
->rerr
!= ___FIX(___NO_ERR
) ||
322 (pipe
->rd
== pipe
->wr
&& !pipe
->oob
))
323 ResetEvent (pipe
->revent
); /* ignore error */
326 ReleaseMutex (pipe
->mutex
); /* ignore error */
331 ___HIDDEN ___SCMOBJ ___nonblocking_pipe_write_ready_wait
332 ___P((___nonblocking_pipe
*pipe
),
334 ___nonblocking_pipe
*pipe
;)
338 if (WaitForSingleObject (pipe
->wevent
, INFINITE
) == WAIT_FAILED
||
339 WaitForSingleObject (pipe
->mutex
, INFINITE
) == WAIT_FAILED
)
340 return err_code_from_GetLastError ();
344 if (rerr
!= ___FIX(___NO_ERR
))
346 pipe
->rerr
= ___FIX(___NO_ERR
);
348 ResetEvent (pipe
->wevent
); /* ignore error */
351 ReleaseMutex (pipe
->mutex
); /* ignore error */
356 ___HIDDEN ___SCMOBJ ___nonblocking_pipe_read
357 ___P((___nonblocking_pipe
*pipe
,
360 ___stream_index
*len_done
,
361 ___nonblocking_pipe_oob_msg
*oob_msg
),
367 ___nonblocking_pipe
*pipe
;
370 ___stream_index
*len_done
;
371 ___nonblocking_pipe_oob_msg
*oob_msg
;)
383 return ___FIX(___UNKNOWN_ERR
);
385 if (WaitForSingleObject (pipe
->mutex
, INFINITE
) == WAIT_FAILED
)
386 return err_code_from_GetLastError ();
393 if (rerr
!= ___FIX(___NO_ERR
))
395 /* there is a reader error */
397 if (werr
== ___FIX(___NO_ERR
))
398 werr
= ___ERR_CODE_EAGAIN
;
401 pipe
->werr
= ___FIX(___NO_ERR
);
402 ResetEvent (pipe
->revent
); /* ignore error */
404 ReleaseMutex (pipe
->mutex
); /* ignore error */
408 /* there is no reader error */
412 /* no bytes in FIFO buffer */
416 /* out-of-band present */
418 *oob_msg
= pipe
->oob_msg
;
420 if (werr
== ___FIX(___NO_ERR
))
422 ResetEvent (pipe
->revent
); /* ignore error */
424 /******************zzzzzzzzzzzzzz****/
425 SetEvent (pipe
->wevent
); /* ignore error */
428 ReleaseMutex (pipe
->mutex
); /* ignore error */
430 return ___FIX(___NO_ERR
);
433 /* out-of-band not present */
435 if (werr
!= ___FIX(___NO_ERR
))
437 /* there is a writer error */
439 pipe
->werr
= ___FIX(___NO_ERR
);
441 ResetEvent (pipe
->revent
); /* ignore error */
442 ReleaseMutex (pipe
->mutex
); /* ignore error */
446 /* there is no writer error */
448 SetEvent (pipe
->wevent
); /* ignore error */
449 ReleaseMutex (pipe
->mutex
); /* ignore error */
450 return ___ERR_CODE_EAGAIN
;
453 /* at least one byte in FIFO buffer */
455 end
= pipe
->size
- rd
; /* number of bytes from rd to end */
457 n
= wr
+ end
; /* number of bytes available */
461 if (n
> ___CAST(DWORD
,len
)) /* don't transfer more than len */
466 p
= pipe
->buffer
+ rd
; /* prepare transfer source */
469 if (rd
>= pipe
->size
)
474 if (werr
== ___FIX(___NO_ERR
) && !pipe
->oob
)
476 /* there is no writer error and out-of-band not present */
478 if (rd
== wr
) /* the FIFO will be empty? */
479 ResetEvent (pipe
->revent
); /* ignore error */
481 /* the FIFO will not be full */
483 SetEvent (pipe
->wevent
); /* ignore error */
488 /* only need to transfer n bytes starting from original rd */
495 /* need to transfer end bytes starting from original rd */
497 for (i
=end
; i
>0; i
--)
500 /* and to transfer n-end bytes starting from 0 */
504 for (i
=n
-end
; i
>0; i
--)
508 ReleaseMutex (pipe
->mutex
); /* ignore error */
510 return ___FIX(___NO_ERR
);
513 ___HIDDEN ___SCMOBJ ___nonblocking_pipe_write
514 ___P((___nonblocking_pipe
*pipe
,
517 ___stream_index
*len_done
),
522 ___nonblocking_pipe
*pipe
;
525 ___stream_index
*len_done
;)
537 return ___FIX(___UNKNOWN_ERR
);
539 if (WaitForSingleObject (pipe
->mutex
, INFINITE
) == WAIT_FAILED
)
540 return err_code_from_GetLastError ();
547 if (werr
!= ___FIX(___NO_ERR
))
549 /* there is a writer error */
551 if (rerr
== ___FIX(___NO_ERR
))
552 rerr
= ___ERR_CODE_EAGAIN
;
555 pipe
->rerr
= ___FIX(___NO_ERR
);
556 ResetEvent (pipe
->wevent
); /* ignore error */
558 ReleaseMutex (pipe
->mutex
); /* ignore error */
562 /* there is no writer error */
564 if (rerr
!= ___FIX(___NO_ERR
))
566 /* there is a reader error */
568 pipe
->rerr
= ___FIX(___NO_ERR
);
570 if (rd
!= wr
|| pipe
->oob
) /* FIFO is not empty */
571 SetEvent (pipe
->revent
); /* ignore error */
573 ResetEvent (pipe
->wevent
); /* ignore error */
574 ReleaseMutex (pipe
->mutex
); /* ignore error */
578 /* there is no reader error */
580 if (wr
+ 1 - rd
== 0 || wr
+ 1 - rd
== pipe
->size
|| pipe
->oob
)
582 /* FIFO buffer is full or out-of-band present */
584 ReleaseMutex (pipe
->mutex
); /* ignore error */
585 return ___ERR_CODE_EAGAIN
;
588 /* FIFO buffer is not full and out-of-band not present */
590 end
= pipe
->size
- wr
; /* number of bytes from wr to end */
592 n
= rd
+ end
- 1; /* number of bytes available */
596 if (n
> ___CAST(DWORD
,len
)) /* don't transfer more than len */
601 p
= pipe
->buffer
+ wr
; /* prepare transfer source */
604 if (wr
>= pipe
->size
)
609 if (wr
+ 1 - rd
== 0 || wr
+ 1 - rd
== pipe
->size
) /* FIFO will be full? */
610 ResetEvent (pipe
->wevent
); /* ignore error */
612 /* FIFO will not be empty */
614 SetEvent (pipe
->revent
); /* ignore error */
618 /* only need to transfer n bytes starting from original wr */
625 /* need to transfer end bytes starting from original wr */
627 for (i
=end
; i
>0; i
--)
630 /* and to transfer n-end bytes starting from 0 */
634 for (i
=n
-end
; i
>0; i
--)
638 ReleaseMutex (pipe
->mutex
); /* ignore error */
640 return ___FIX(___NO_ERR
);
646 /*---------------------------------------------------------------------------*/
648 /* Operations on I/O devices. */
650 /* Miscellaneous utility functions. */
656 typedef sigset_t sigset_type
;
658 typedef int sigset_type
;
662 ___HIDDEN sigset_type block_signal
673 sigemptyset (&toblock
);
674 sigaddset (&toblock
, signum
);
675 sigprocmask (SIG_BLOCK
, &toblock
, &oldmask
);
681 oldmask
= sigblock (sigmask (signum
));
689 ___HIDDEN
void restore_sigmask
690 ___P((sigset_type oldmask
),
692 sigset_type oldmask
;)
696 sigprocmask (SIG_SETMASK
, &oldmask
, 0);
702 sigsetmask (oldmask
);
709 * Some system calls can be interrupted by a signal and fail with
710 * errno == EINTR. The following functions are wrappers for system
711 * calls which may be interrupted. They simply ignore the EINTR and
712 * retry the operation.
714 * TODO: add wrappers for all the system calls which can fail
715 * with EINTR. Also, move these functions to a central place.
718 pid_t waitpid_no_EINTR
733 result
= waitpid (pid
, stat_loc
, options
);
734 if (result
>= 0 || errno
!= EINTR
)
742 ssize_t read_no_EINTR
753 char *p
= ___CAST(char*,buf
);
759 n
= read (fd
, p
+result
, len
-result
);
764 else if (errno
!= EINTR
)
765 return n
; /* this forgets that some bytes were transferred */
782 if (result
>= 0 || errno
!= EINTR
)
800 if (result
>= 0 || errno
!= EINTR
)
820 result
= dup2 (fd
, fd2
);
821 if (result
>= 0 || errno
!= EINTR
)
829 int set_fd_blocking_mode
839 if ((fl
= fcntl (fd
, F_GETFL
, 0)) >= 0)
842 blocking
? (fl
& ~O_NONBLOCK
) : (fl
| O_NONBLOCK
));
850 /*---------------------------------------------------------------------------*/
852 /* Generic device operations. */
854 ___SCMOBJ ___device_select
855 ___P((___device
**devs
,
869 ___device_select_state state
;
876 nb_devs
= nb_read_devs
+ nb_write_devs
;
880 state
.timeout
= timeout
;
881 state
.relative_timeout
= POS_INFINITY
;
885 state
.highest_fd_plus_1
= 0;
887 FD_ZERO(&state
.readfds
);
888 FD_ZERO(&state
.writefds
);
889 FD_ZERO(&state
.exceptfds
);
893 #ifdef USE_MsgWaitForMultipleObjects
895 state
.message_queue_mask
= 0;
896 state
.message_queue_dev_pos
= -1;
898 state
.wait_objs_buffer
[0] = ___io_mod
.abort_select
;
899 state
.wait_objs_buffer
[1] = ___time_mod
.heartbeat_thread
;
901 state
.nb_wait_objs
= 2;
907 state
.devs_next
[nb_devs
-1] = -1;
909 for (i
=nb_devs
-2; i
>=0; i
--)
910 state
.devs_next
[i
] = i
+1;
917 pass
= ___SELECT_PASS_1
;
919 while (dev_list
!= -1)
927 ___device
*d
= devs
[i
];
928 if ((e
= ___device_select_virt
934 == ___FIX(___NO_ERR
))
937 i
= state
.devs_next
[i
];
942 if (e
!= ___FIX(___SELECT_SETUP_DONE
))
944 j
= state
.devs_next
[i
];
948 state
.devs_next
[prev
] = j
;
949 #ifdef USE_MsgWaitForMultipleObjects
950 state
.devs_next
[i
] = -1;
959 ___absolute_time_to_relative_time (state
.timeout
, &delta
);
961 if (___time_less (state
.relative_timeout
, delta
))
963 delta
= state
.relative_timeout
;
964 state
.timeout
= ___time_mod
.time_neg_infinity
;
967 state
.relative_timeout
= NEG_INFINITY
;
972 struct timeval delta_tv_struct
;
973 struct timeval
*delta_tv
= &delta_tv_struct
;
976 ___absolute_time_to_nonnegative_timeval (delta
, &delta_tv
);
978 if (delta_tv
!= NULL
&&
979 state
.highest_fd_plus_1
== 0)
982 * ___device_select is only being called for sleeping until a
983 * certain timeout or interrupt occurs. This is a case that
987 if (delta_tv
->tv_sec
< 0 ||
988 (delta_tv
->tv_sec
== 0 &&
989 delta_tv
->tv_usec
== 0))
992 * The timeout has already passed, so we don't need to
993 * sleep. This simple optimization avoids doing a system
994 * call to the select or nanosleep functions (which can be
995 * expensive on some operating systems).
1002 #ifdef USE_nanosleep
1007 * For better timeout resolution, the nanosleep function
1008 * is used instead of the select function. On some
1009 * operating systems (e.g. OpenBSD 4.5) the nanosleep
1010 * function can be more expensive than a call to select,
1011 * but the better timeout resolution outweighs the run
1015 struct timespec delta_ts_struct
;
1016 delta_ts_struct
.tv_sec
= delta_tv
->tv_sec
;
1017 delta_ts_struct
.tv_nsec
= delta_tv
->tv_usec
* 1000;
1018 result
= nanosleep (&delta_ts_struct
, NULL
);
1026 * Heartbeat interrupts must be disabled in case they are based on the
1027 * real-time timer. This is needed to bypass issues in two buggy
1028 * operating systems:
1030 * - On MacOS X, the virtual-time timer does not fire at the correct
1031 * rate (apparently this happens only on machines with more than
1034 * - On CYGWIN, the select system call can be interrupted by the
1035 * timer and in some cases the error "No child processes" will
1036 * be returned by select.
1039 ___disable_heartbeat_interrupts ();
1042 select (state
.highest_fd_plus_1
,
1048 ___enable_heartbeat_interrupts ();
1053 return err_code_from_errno ();
1055 state
.timeout_reached
= (result
== 0);
1060 #ifdef USE_MsgWaitForMultipleObjects
1064 int first_iteration
= TRUE
;
1066 ___absolute_time_to_nonnegative_msecs (delta
, &delta_msecs
);
1068 state
.timeout_reached
= 0;
1070 while (state
.nb_wait_objs
> 0 || state
.message_queue_mask
!= 0)
1074 n
= MsgWaitForMultipleObjects
1075 (state
.nb_wait_objs
,
1076 state
.wait_objs_buffer
,
1079 state
.message_queue_mask
);
1081 if (n
== WAIT_FAILED
)
1082 return err_code_from_GetLastError ();
1084 if ((n
- WAIT_OBJECT_0
) <= WAIT_OBJECT_0
+ state
.nb_wait_objs
)
1086 else if (n
>= WAIT_ABANDONED_0
&&
1087 n
<= WAIT_ABANDONED_0
+state
.nb_wait_objs
-1)
1088 n
-= WAIT_ABANDONED_0
;
1091 /* n == WAIT_TIMEOUT */
1094 * The call to MsgWaitForMultipleObjects timed out. Mark
1095 * the appropriate device "ready".
1098 if (first_iteration
)
1100 /* first call to MsgWaitForMultipleObjects */
1102 state
.timeout_reached
= 1;
1108 if (n
== state
.nb_wait_objs
)
1111 * The message queue contains a message that is of interest.
1112 * Mark the appropriate device "ready".
1115 i
= state
.message_queue_dev_pos
;
1117 state
.devs_next
[i
] = 0;
1120 * Don't check if other devices are ready because this might
1121 * cause an infinite loop.
1129 * The call to ___device_select must be aborted because the
1130 * abort_select event is set. This occurs when an interrupt
1131 * (such as a CTRL-C user interrupt) needs to be serviced
1132 * promptly by the main program.
1135 ResetEvent (___io_mod
.abort_select
); /* ignore error */
1137 return ___FIX(___ERRNO_ERR(EINTR
));
1142 * The heartbeat thread has died. This is normally due to
1143 * the program being terminated abruptly by the user (for
1144 * example by using the thread manager or the "shutdown"
1145 * item in the start menu). When this happens we must
1146 * initiate a clean termination of the program.
1149 return ___FIX(___UNKNOWN_ERR
);
1153 /* Mark the appropriate device "ready". */
1155 i
= state
.wait_obj_to_dev_pos
[n
];
1157 state
.devs_next
[i
] = 0;
1159 /* Prepare to check remaining devices. */
1161 state
.nb_wait_objs
--;
1163 state
.wait_objs_buffer
[n
] =
1164 state
.wait_objs_buffer
[state
.nb_wait_objs
];
1166 state
.wait_obj_to_dev_pos
[n
] =
1167 state
.wait_obj_to_dev_pos
[state
.nb_wait_objs
];
1170 first_iteration
= FALSE
;
1171 delta_msecs
= 0; /* next MsgWaitForMultipleObjects will only poll */
1177 for (i
=nb_devs
-1; i
>=0; i
--)
1180 ___device
*d
= devs
[i
];
1182 if ((e
= ___device_select_virt
1186 ___SELECT_PASS_CHECK
,
1188 != ___FIX(___NO_ERR
))
1192 return ___FIX(___NO_ERR
);
1196 void ___device_select_add_relative_timeout
1197 ___P((___device_select_state
*state
,
1203 ___device_select_state
*state
;
1207 if (seconds
< state
->relative_timeout
)
1208 state
->relative_timeout
= seconds
;
1212 void ___device_select_add_timeout
1213 ___P((___device_select_state
*state
,
1219 ___device_select_state
*state
;
1223 if (___time_less (timeout
, state
->timeout
))
1224 state
->timeout
= timeout
;
1230 void ___device_select_add_fd
1231 ___P((___device_select_state
*state
,
1233 ___BOOL for_writing
),
1237 ___device_select_state
*state
;
1239 ___BOOL for_writing
;)
1242 FD_SET(fd
, &state
->writefds
);
1244 FD_SET(fd
, &state
->readfds
);
1246 if (fd
>= state
->highest_fd_plus_1
)
1247 state
->highest_fd_plus_1
= fd
+1;
1253 #ifdef USE_MsgWaitForMultipleObjects
1255 void ___device_select_add_wait_obj
1256 ___P((___device_select_state
*state
,
1262 ___device_select_state
*state
;
1266 DWORD j
= state
->nb_wait_objs
;
1268 if (j
< MAXIMUM_WAIT_OBJECTS
)
1270 state
->wait_objs_buffer
[j
] = wait_obj
;
1271 state
->wait_obj_to_dev_pos
[j
] = i
;
1272 state
->nb_wait_objs
= j
+1;
1279 ___SCMOBJ ___device_force_output
1280 ___P((___device
*self
,
1287 return ___device_force_output_virt (self
, level
);
1290 ___SCMOBJ ___device_close
1291 ___P((___device
*self
,
1298 return ___device_close_virt (self
, direction
);
1301 ___HIDDEN
void device_transfer_close_responsibility
1302 ___P((___device
*self
),
1307 * Transfer responsibility for closing device to the runtime system.
1310 self
->close_direction
= self
->direction
;
1313 ___HIDDEN
void device_add_ref
1314 ___P((___device
*self
),
1319 InterlockedIncrement (&self
->refcount
);
1325 ___SCMOBJ ___device_release
1326 ___P((___device
*self
),
1330 ___SCMOBJ e
= ___FIX(___NO_ERR
);
1334 InterlockedDecrement (&self
->refcount
) == 0
1336 --self
->refcount
== 0
1340 e
= ___device_release_virt (self
);
1347 ___SCMOBJ ___device_cleanup
1348 ___P((___device
*self
),
1355 if (self
->group
== NULL
)
1356 return ___FIX(___UNKNOWN_ERR
);
1358 ___device_remove_from_group (self
);
1362 e
= ___device_close (self
, ___DIRECTION_RD
);
1363 if (e
== ___FIX(___NO_ERR
))
1365 if (e
!= ___ERR_CODE_EAGAIN
)
1369 e
= ___device_select (devs
, 1, 0, ___time_mod
.time_pos_infinity
);
1370 if (e
!= ___FIX(___NO_ERR
))
1376 e
= ___device_close (self
, ___DIRECTION_WR
);
1377 if (e
== ___FIX(___NO_ERR
))
1379 if (e
!= ___ERR_CODE_EAGAIN
)
1383 e
= ___device_select (devs
, 0, 1, ___time_mod
.time_pos_infinity
);
1384 if (e
!= ___FIX(___NO_ERR
))
1388 return ___device_release (self
);
1393 * Procedure called by the Scheme runtime when a device is no longer
1397 ___SCMOBJ ___device_cleanup_from_ptr
1402 return ___device_cleanup (___CAST(___device
*,ptr
));
1406 /* - - - - - - - - - - - - - - - - - - */
1411 * Timer devices are not particularly useful, given that the scheduler
1412 * implements timeouts. Use this as an example.
1415 ___HIDDEN
int device_timer_kind
1416 ___P((___device
*self
),
1420 return ___TIMER_KIND
;
1423 ___HIDDEN ___SCMOBJ device_timer_select_virt
1424 ___P((___device
*self
,
1425 ___BOOL for_writing
,
1428 ___device_select_state
*state
),
1435 ___BOOL for_writing
;
1438 ___device_select_state
*state
;)
1440 ___device_timer
*d
= ___CAST(___device_timer
*,self
);
1442 if (pass
== ___SELECT_PASS_1
)
1444 if (___time_less (d
->expiry
, state
->timeout
))
1445 state
->timeout
= d
->expiry
;
1446 return ___FIX(___SELECT_SETUP_DONE
);
1449 /* pass == ___SELECT_PASS_CHECK */
1451 if (state
->timeout_reached
)
1453 if (___time_equal (d
->expiry
, state
->timeout
))
1454 state
->devs
[i
] = NULL
;
1457 return ___FIX(___NO_ERR
);
1460 ___HIDDEN ___SCMOBJ device_timer_release_virt
1461 ___P((___device
*self
),
1465 return ___FIX(___NO_ERR
);
1468 ___HIDDEN ___SCMOBJ device_timer_force_output_virt
1469 ___P((___device
*self
,
1476 return ___FIX(___NO_ERR
);
1479 ___HIDDEN ___SCMOBJ device_timer_close_virt
1480 ___P((___device
*self
,
1487 return ___FIX(___NO_ERR
);
1490 ___HIDDEN ___device_timer_vtbl ___device_timer_table
=
1494 device_timer_select_virt
,
1495 device_timer_release_virt
,
1496 device_timer_force_output_virt
,
1497 device_timer_close_virt
1501 ___SCMOBJ ___device_timer_setup
1502 ___P((___device_timer
**dev
,
1503 ___device_group
*dgroup
),
1506 ___device_timer
**dev
;
1507 ___device_group
*dgroup
;)
1511 d
= ___CAST(___device_timer
*,
1512 ___alloc_mem (sizeof (___device_timer
)));
1515 return ___FIX(___HEAP_OVERFLOW_ERR
);
1517 d
->base
.vtbl
= &___device_timer_table
;
1518 d
->base
.refcount
= 1;
1519 d
->base
.direction
= ___DIRECTION_RD
| ___DIRECTION_WR
;
1520 d
->base
.close_direction
= 0; /* prevent closing on errors */
1521 d
->base
.read_stage
= ___STAGE_OPEN
;
1522 d
->base
.write_stage
= ___STAGE_OPEN
;
1524 d
->expiry
= ___time_mod
.time_pos_infinity
;
1528 ___device_add_to_group (dgroup
, &d
->base
);
1530 return ___FIX(___NO_ERR
);
1533 void ___device_timer_set_expiry
1534 ___P((___device_timer
*dev
,
1538 ___device_timer
*dev
;
1541 dev
->expiry
= expiry
;
1544 /* - - - - - - - - - - - - - - - - - - */
1546 /* Byte stream devices. */
1550 ___HIDDEN ___SCMOBJ ___device_stream_pump_setup
1551 ___P((___device_stream_pump
**pump
,
1552 DWORD committed_stack_size
,
1553 LPTHREAD_START_ROUTINE proc
,
1556 committed_stack_size
,
1559 ___device_stream_pump
**pump
;
1560 DWORD committed_stack_size
;
1561 LPTHREAD_START_ROUTINE proc
;
1565 ___device_stream_pump
*p
;
1566 HANDLE thread_handle
;
1569 p
= ___CAST(___device_stream_pump
*,
1570 ___alloc_mem (sizeof (___device_stream_pump
)));
1573 return ___FIX(___HEAP_OVERFLOW_ERR
);
1575 e
= ___nonblocking_pipe_setup (&p
->pipe
, PIPE_BUFFER_SIZE
+1);
1577 if (e
!= ___FIX(___NO_ERR
))
1583 *pump
= p
; /* set before thread created to avoid race condition */
1586 CreateThread (NULL
, /* no security attributes */
1587 committed_stack_size
, /* committed stack size */
1588 proc
, /* thread procedure */
1589 arg
, /* argument to thread procedure */
1590 0, /* use default creation flags */
1593 if (thread_handle
== NULL
||
1594 !SetThreadPriority (thread_handle
, PUMP_PRIORITY
))
1596 e
= err_code_from_GetLastError ();
1597 ___nonblocking_pipe_cleanup (&p
->pipe
);
1599 *pump
= NULL
; /* make sure caller does not think a pump was created */
1603 p
->thread
= thread_handle
;
1605 return ___FIX(___NO_ERR
);
1608 ___HIDDEN ___SCMOBJ ___device_stream_pump_reader_kill
1609 ___P((___device_stream_pump
*pump
),
1611 ___device_stream_pump
*pump
;)
1613 return ___nonblocking_pipe_set_reader_err
1615 ___FIX(___KILL_PUMP
));
1618 ___HIDDEN ___SCMOBJ ___device_stream_pump_writer_kill
1619 ___P((___device_stream_pump
*pump
),
1621 ___device_stream_pump
*pump
;)
1623 return ___nonblocking_pipe_set_writer_err
1625 ___FIX(___KILL_PUMP
));
1628 ___HIDDEN ___SCMOBJ ___device_stream_pump_wait
1629 ___P((___device_stream_pump
*pump
),
1631 ___device_stream_pump
*pump
;)
1635 code
= WaitForSingleObject (pump
->thread
, 0);
1637 if (code
== WAIT_FAILED
)
1638 return err_code_from_GetLastError ();
1640 if (code
== WAIT_TIMEOUT
)
1641 return ___ERR_CODE_EAGAIN
;
1643 return ___FIX(___NO_ERR
);
1646 ___HIDDEN ___SCMOBJ ___device_stream_pump_cleanup
1647 ___P((___device_stream_pump
*pump
),
1649 ___device_stream_pump
*pump
;)
1651 CloseHandle (pump
->thread
); /* ignore error */
1652 ___nonblocking_pipe_cleanup (&pump
->pipe
); /* ignore error */
1655 return ___FIX(___NO_ERR
);
1660 ___SCMOBJ ___device_stream_select_virt
1661 ___P((___device
*self
,
1662 ___BOOL for_writing
,
1665 ___device_select_state
*state
),
1672 ___BOOL for_writing
;
1675 ___device_select_state
*state
;)
1677 ___device_stream
*d
= ___CAST(___device_stream
*,self
);
1681 int stage
= (for_writing
1682 ? d
->base
.write_stage
1683 : d
->base
.read_stage
);
1684 ___device_stream_pump
*p
= (for_writing
1690 if (pass
== ___SELECT_PASS_1
)
1694 if (stage
!= ___STAGE_OPEN
)
1695 wait_obj
= p
->thread
;
1699 wait_obj
= p
->pipe
.wevent
;
1701 wait_obj
= p
->pipe
.revent
;
1704 ___device_select_add_wait_obj (state
, i
, wait_obj
);
1706 return ___FIX(___SELECT_SETUP_DONE
);
1709 /* pass == ___SELECT_PASS_CHECK */
1711 if (stage
!= ___STAGE_OPEN
)
1712 state
->devs
[i
] = NULL
;
1715 if (state
->devs_next
[i
] != -1)
1716 state
->devs
[i
] = NULL
;
1719 return ___FIX(___NO_ERR
);
1724 return ___device_stream_select_raw_virt
1733 ___SCMOBJ ___device_stream_release_virt
1734 ___P((___device
*self
),
1739 ___device_stream
*d
= ___CAST(___device_stream
*,self
);
1741 e
= ___device_stream_release_raw_virt (d
);
1746 ___device_stream_pump
*p
;
1750 ___device_stream_pump_cleanup (p
); /* ignore error */
1754 ___device_stream_pump_cleanup (p
); /* ignore error */
1763 ___SCMOBJ ___device_stream_force_output_virt
1764 ___P((___device
*self
,
1771 ___device_stream
*d
= ___CAST(___device_stream
*,self
);
1776 ___device_stream_pump
*p
= d
->write_pump
;
1780 ___nonblocking_pipe_oob_msg oob_msg
;
1782 oob_msg
.op
= OOB_FORCE_OUTPUT0
+ level
;
1784 return ___nonblocking_pipe_write_oob (&p
->pipe
, &oob_msg
);
1790 return ___device_stream_force_output_raw_virt (d
, level
);
1794 ___SCMOBJ ___device_stream_close_virt
1795 ___P((___device
*self
,
1802 ___device_stream
*d
= ___CAST(___device_stream
*,self
);
1806 if (direction
& ___DIRECTION_RD
)
1808 ___device_stream_pump
*p
= d
->read_pump
;
1811 ___device_stream_pump_reader_kill (p
);
1814 if (direction
& ___DIRECTION_WR
)
1816 ___device_stream_pump
*p
= d
->write_pump
;
1819 ___device_stream_pump_writer_kill (p
);
1824 return ___device_stream_close_raw_virt (d
, direction
);
1828 ___SCMOBJ ___device_stream_seek
1829 ___P((___device_stream
*self
,
1830 ___stream_index
*pos
,
1835 ___device_stream
*self
;
1836 ___stream_index
*pos
;
1842 ___device_stream_pump
*p
= self
->write_pump
;
1846 ___nonblocking_pipe_oob_msg oob_msg
;
1848 oob_msg
.op
= OOB_SEEK_ABS
+ whence
;
1849 oob_msg
.stream_index_param
= *pos
;
1851 return ___nonblocking_pipe_write_oob (&p
->pipe
, &oob_msg
);
1857 return ___device_stream_seek_raw_virt (self
, pos
, whence
);
1860 ___SCMOBJ ___device_stream_read
1861 ___P((___device_stream
*self
,
1863 ___stream_index len
,
1864 ___stream_index
*len_done
),
1869 ___device_stream
*self
;
1871 ___stream_index len
;
1872 ___stream_index
*len_done
;)
1877 ___device_stream_pump
*p
= self
->read_pump
;
1881 ___nonblocking_pipe_oob_msg oob_msg
;
1882 return ___nonblocking_pipe_read
1893 return ___device_stream_read_raw_virt (self
, buf
, len
, len_done
);
1896 ___SCMOBJ ___device_stream_write
1897 ___P((___device_stream
*self
,
1899 ___stream_index len
,
1900 ___stream_index
*len_done
),
1905 ___device_stream
*self
;
1907 ___stream_index len
;
1908 ___stream_index
*len_done
;)
1913 ___device_stream_pump
*p
= self
->write_pump
;
1916 return ___nonblocking_pipe_write (&p
->pipe
, buf
, len
, len_done
);
1921 return ___device_stream_write_raw_virt (self
, buf
, len
, len_done
);
1924 /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */
1928 ___HIDDEN DWORD WINAPI ___device_stream_read_pump_proc
1929 ___P((LPVOID param
),
1933 ___device_stream
*dev
= ___CAST(___device_stream
*,param
);
1934 ___nonblocking_pipe
*p
= &dev
->read_pump
->pipe
;
1936 ___stream_index len
;
1939 ___U8 buf
[PIPE_BUFFER_SIZE
];
1940 ___nonblocking_pipe_oob_msg oob_msg
;
1944 /* wait until the reader needs some data */
1946 e
= ___nonblocking_pipe_write_ready_wait (p
);
1948 /* read some characters from device */
1950 if (e
== ___FIX(___NO_ERR
))
1951 e
= ___device_stream_read_raw_virt (dev
, buf
, PIPE_BUFFER_SIZE
, &len
);
1953 if (e
== ___FIX(___NO_ERR
))
1957 /* we reached the end-of-stream */
1959 oob_msg
.op
= OOB_EOS
;
1961 while ((e
= ___nonblocking_pipe_write_oob (p
, &oob_msg
))
1962 == ___ERR_CODE_EAGAIN
)
1964 /* suspend thread until operation can be performed */
1966 e
= ___nonblocking_pipe_write_ready_wait (p
);
1967 if (e
!= ___FIX(___NO_ERR
))
1970 if (e
!= ___FIX(___NO_ERR
))
1975 /* write to the pipe the bytes that were read */
1981 while ((e
= ___nonblocking_pipe_write (p
, buf
+i
, len
-i
, &n
))
1982 == ___ERR_CODE_EAGAIN
)
1984 /* suspend thread until operation can be performed */
1986 e
= ___nonblocking_pipe_write_ready_wait (p
);
1987 if (e
!= ___FIX(___NO_ERR
))
1990 if (e
!= ___FIX(___NO_ERR
))
1997 if (e
!= ___FIX(___NO_ERR
))
1999 if (e
== ___FIX(___KILL_PUMP
)) /* terminate? */
2002 if (e
== ___ERR_CODE_EAGAIN
)
2005 /* report the failure back through the pipe */
2007 e
= ___nonblocking_pipe_set_writer_err (p
, e
);
2009 if (e
!= ___FIX(___NO_ERR
))
2012 * The failure could not be reported. To avoid an
2013 * infinite loop the thread is terminated.
2021 ___device_release (&dev
->base
); /* ignore error */
2026 ___HIDDEN DWORD WINAPI ___device_stream_write_pump_proc
2027 ___P((LPVOID param
),
2031 ___device_stream
*dev
= ___CAST(___device_stream
*,param
);
2032 ___nonblocking_pipe
*p
= &dev
->write_pump
->pipe
;
2034 ___stream_index len
;
2037 ___U8 buf
[PIPE_BUFFER_SIZE
];
2038 ___nonblocking_pipe_oob_msg oob_msg
;
2042 /* get from the pipe some bytes to write to the device */
2044 while ((e
= ___nonblocking_pipe_read
2050 == ___ERR_CODE_EAGAIN
)
2052 /* suspend thread until operation can be performed */
2054 e
= ___nonblocking_pipe_read_ready_wait (p
);
2055 if (e
!= ___FIX(___NO_ERR
))
2059 if (e
== ___FIX(___NO_ERR
))
2063 /* write to the device the bytes that were read from the pipe */
2069 e
= ___device_stream_write_raw_virt (dev
, buf
+i
, len
-i
, &n
);
2070 if (e
!= ___FIX(___NO_ERR
))
2079 case OOB_FORCE_OUTPUT0
:
2080 case OOB_FORCE_OUTPUT1
:
2081 case OOB_FORCE_OUTPUT2
:
2082 case OOB_FORCE_OUTPUT3
:
2084 ___printf ("***** got OOB_FORCE_OUTPUT%d\n",
2085 oob_msg
.op
- OOB_FORCE_OUTPUT0
);
2087 e
= ___device_stream_force_output_raw_virt (dev
, oob_msg
.op
- OOB_FORCE_OUTPUT0
);
2091 case OOB_SEEK_REL_END
:
2093 ___printf ("***** got OOB_SEEK %d %d\n",
2094 oob_msg
.stream_index_param
,
2095 oob_msg
.op
- OOB_SEEK_ABS
);
2097 e
= ___device_stream_seek_raw_virt
2099 &oob_msg
.stream_index_param
,
2100 oob_msg
.op
- OOB_SEEK_ABS
);
2104 ___printf ("***** got OOB_EOS\n");
2111 if (e
!= ___FIX(___NO_ERR
))
2113 if (e
== ___FIX(___KILL_PUMP
)) /* terminate? */
2116 /* report the failure back through the pipe */
2118 e
= ___nonblocking_pipe_set_reader_err (p
, e
);
2120 if (e
!= ___FIX(___NO_ERR
))
2123 * The failure could not be reported. To avoid an
2124 * infinite loop the thread is terminated.
2132 ___device_release (&dev
->base
); /* ignore error */
2139 ___SCMOBJ ___device_stream_setup
2140 ___P((___device_stream
*dev
,
2141 ___device_group
*dgroup
,
2147 pumps_on
)/*********************/
2148 ___device_stream
*dev
;
2149 ___device_group
*dgroup
;
2153 dev
->base
.refcount
= 1;
2154 dev
->base
.direction
= direction
;
2155 dev
->base
.close_direction
= 0; /* prevent closing on errors */
2156 dev
->base
.read_stage
= ___STAGE_CLOSED
;
2157 dev
->base
.write_stage
= ___STAGE_CLOSED
;
2160 dev
->read_pump
= NULL
;
2161 dev
->write_pump
= NULL
;
2164 ___device_add_to_group (dgroup
, &dev
->base
);
2166 if (direction
& ___DIRECTION_RD
)
2168 dev
->base
.read_stage
= ___STAGE_OPEN
;
2172 if (pumps_on
& ___DIRECTION_RD
)
2176 device_add_ref (&dev
->base
);
2178 if ((e
= ___device_stream_pump_setup
2181 ___device_stream_read_pump_proc
,
2183 != ___FIX(___NO_ERR
))
2185 ___device_release (&dev
->base
); /* ignore error */
2186 ___device_cleanup (&dev
->base
); /* ignore error */
2194 if (direction
& ___DIRECTION_WR
)
2196 dev
->base
.write_stage
= ___STAGE_OPEN
;
2200 if (pumps_on
& ___DIRECTION_WR
)
2204 device_add_ref (&dev
->base
);
2206 if ((e
= ___device_stream_pump_setup
2209 ___device_stream_write_pump_proc
,
2211 != ___FIX(___NO_ERR
))
2213 ___device_release (&dev
->base
); /* ignore error */
2214 ___device_cleanup (&dev
->base
); /* ignore error */
2222 return ___FIX(___NO_ERR
);
2226 /*---------------------------------------------------------------------------*/
2228 /* Serial stream device */
2232 typedef struct ___device_serial_struct
2234 ___device_stream base
;
2238 typedef struct ___device_serial_vtbl_struct
2240 ___device_stream_vtbl base
;
2241 } ___device_serial_vtbl
;
2243 ___HIDDEN
int ___device_serial_kind
2244 ___P((___device
*self
),
2248 return ___SERIAL_DEVICE_KIND
;
2251 ___HIDDEN ___SCMOBJ ___device_serial_close_raw_virt
2252 ___P((___device_stream
*self
,
2256 ___device_stream
*self
;
2259 ___device_serial
*d
= ___CAST(___device_serial
*,self
);
2260 int is_not_closed
= 0;
2262 if (d
->base
.base
.read_stage
!= ___STAGE_CLOSED
)
2263 is_not_closed
|= ___DIRECTION_RD
;
2265 if (d
->base
.base
.write_stage
!= ___STAGE_CLOSED
)
2266 is_not_closed
|= ___DIRECTION_WR
;
2268 if (is_not_closed
== 0)
2269 return ___FIX(___NO_ERR
);
2271 if (is_not_closed
== (___DIRECTION_RD
|___DIRECTION_WR
))
2273 d
->base
.base
.read_stage
= ___STAGE_CLOSED
;
2274 d
->base
.base
.write_stage
= ___STAGE_CLOSED
;
2276 if ((d
->base
.base
.close_direction
& (___DIRECTION_RD
|___DIRECTION_WR
))
2277 == (___DIRECTION_RD
|___DIRECTION_WR
))
2279 if (!CloseHandle (d
->h
))
2280 return err_code_from_GetLastError ();
2284 return ___FIX(___NO_ERR
);
2287 ___HIDDEN ___SCMOBJ ___device_serial_select_raw_virt
2288 ___P((___device_stream
*self
,
2289 ___BOOL for_writing
,
2292 ___device_select_state
*state
),
2298 ___device_stream
*self
;
2299 ___BOOL for_writing
;
2302 ___device_select_state
*state
;)
2304 ___device_serial
*d
= ___CAST(___device_serial
*,self
);
2305 int stage
= (for_writing
2306 ? d
->base
.base
.write_stage
2307 : d
->base
.base
.read_stage
);
2309 if (pass
== ___SELECT_PASS_1
)
2311 if (stage
!= ___STAGE_OPEN
)
2312 state
->timeout
= ___time_mod
.time_neg_infinity
;
2313 return ___FIX(___SELECT_SETUP_DONE
);
2316 /* pass == ___SELECT_PASS_CHECK */
2318 if (stage
!= ___STAGE_OPEN
)
2319 state
->devs
[i
] = NULL
;
2322 if (state
->devs_next
[i
] != -1)
2323 state
->devs
[i
] = NULL
;
2326 return ___FIX(___NO_ERR
);
2329 ___HIDDEN ___SCMOBJ ___device_serial_release_raw_virt
2330 ___P((___device_stream
*self
),
2332 ___device_stream
*self
;)
2334 return ___FIX(___NO_ERR
);
2337 ___HIDDEN ___SCMOBJ ___device_serial_force_output_raw_virt
2338 ___P((___device_stream
*self
,
2342 ___device_stream
*self
;
2345 ___device_serial
*d
= ___CAST(___device_serial
*,self
);
2347 if (d
->base
.base
.write_stage
== ___STAGE_OPEN
)
2351 if (!FlushFileBuffers (d
->h
))
2352 return err_code_from_GetLastError ();
2356 return ___FIX(___NO_ERR
);
2359 ___HIDDEN ___SCMOBJ ___device_serial_seek_raw_virt
2360 ___P((___device_stream
*self
,
2361 ___stream_index
*pos
,
2366 ___device_stream
*self
;
2367 ___stream_index
*pos
;
2370 return ___FIX(___INVALID_OP_ERR
);
2373 ___HIDDEN ___SCMOBJ ___device_serial_read_raw_virt
2374 ___P((___device_stream
*self
,
2376 ___stream_index len
,
2377 ___stream_index
*len_done
),
2382 ___device_stream
*self
;
2384 ___stream_index len
;
2385 ___stream_index
*len_done
;)
2387 ___device_serial
*d
= ___CAST(___device_serial
*,self
);
2389 if (d
->base
.base
.read_stage
!= ___STAGE_OPEN
)
2390 return ___FIX(___CLOSED_DEVICE_ERR
);
2395 if (!ReadFile (d
->h
, buf
, len
, &n
, NULL
))
2396 return err_code_from_GetLastError ();
2399 return ___ERR_CODE_EAGAIN
;
2404 return ___FIX(___NO_ERR
);
2407 ___HIDDEN ___SCMOBJ ___device_serial_write_raw_virt
2408 ___P((___device_stream
*self
,
2410 ___stream_index len
,
2411 ___stream_index
*len_done
),
2416 ___device_stream
*self
;
2418 ___stream_index len
;
2419 ___stream_index
*len_done
;)
2421 ___device_serial
*d
= ___CAST(___device_serial
*,self
);
2423 if (d
->base
.base
.write_stage
!= ___STAGE_OPEN
)
2424 return ___FIX(___CLOSED_DEVICE_ERR
);
2429 if (!WriteFile (d
->h
, buf
, len
, &n
, NULL
))
2432 * Even though WriteFile has reported a failure, the operation
2433 * was executed correctly (i.e. len_done contains the number
2434 * of bytes written) if GetLastError returns ERROR_SUCCESS.
2437 if (GetLastError () != ERROR_SUCCESS
)
2438 return err_code_from_GetLastError ();
2444 return ___FIX(___NO_ERR
);
2447 ___HIDDEN ___SCMOBJ ___device_serial_width_virt
2448 ___P((___device_stream
*self
),
2450 ___device_stream
*self
;)
2455 ___HIDDEN ___SCMOBJ ___device_serial_default_options_virt
2456 ___P((___device_stream
*self
),
2458 ___device_stream
*self
;)
2460 int char_encoding_errors
= ___CHAR_ENCODING_ERRORS_ON
;
2461 int char_encoding
= ___CHAR_ENCODING_ISO_8859_1
;
2462 int eol_encoding
= ___EOL_ENCODING_LF
;
2463 int buffering
= ___FULL_BUFFERING
;
2465 return ___FIX(___STREAM_OPTIONS(char_encoding_errors
,
2469 char_encoding_errors
,
2476 ___HIDDEN ___SCMOBJ ___device_serial_options_set_virt
2477 ___P((___device_stream
*self
,
2481 ___device_stream
*self
;
2484 return ___FIX(___NO_ERR
);
2488 ___HIDDEN ___device_serial_vtbl ___device_serial_table
=
2492 ___device_serial_kind
,
2493 ___device_stream_select_virt
,
2494 ___device_stream_release_virt
,
2495 ___device_stream_force_output_virt
,
2496 ___device_stream_close_virt
2498 ___device_serial_select_raw_virt
,
2499 ___device_serial_release_raw_virt
,
2500 ___device_serial_force_output_raw_virt
,
2501 ___device_serial_close_raw_virt
,
2502 ___device_serial_seek_raw_virt
,
2503 ___device_serial_read_raw_virt
,
2504 ___device_serial_write_raw_virt
,
2505 ___device_serial_width_virt
,
2506 ___device_serial_default_options_virt
,
2507 ___device_serial_options_set_virt
2512 ___HIDDEN ___SCMOBJ ___device_serial_set_comm_state
2513 ___P((___device_serial
*dev
,
2517 ___device_serial
*dev
;
2522 FillMemory (&dcb
, sizeof (dcb
), 0);
2524 if (!GetCommState (dev
->h
, &dcb
) ||
2525 !BuildCommDCB (def
, &dcb
) ||
2526 !SetCommState (dev
->h
, &dcb
))
2527 return err_code_from_GetLastError ();
2529 return ___FIX(___NO_ERR
);
2532 ___SCMOBJ ___device_serial_setup_from_handle
2533 ___P((___device_serial
**dev
,
2534 ___device_group
*dgroup
,
2541 ___device_serial
**dev
;
2542 ___device_group
*dgroup
;
2546 ___device_serial
*d
;
2550 d
= ___CAST(___device_serial
*,
2551 ___alloc_mem (sizeof (___device_serial
)));
2554 return ___FIX(___HEAP_OVERFLOW_ERR
);
2556 d
->base
.base
.vtbl
= &___device_serial_table
;
2561 e
= ___device_serial_set_comm_state (d
, _T("baud=38400 parity=N data=8 stop=1"));
2563 if (e
!= ___FIX(___NO_ERR
))
2570 * Setup serial device so that ReadFile will return as soon as a
2571 * character is available.
2574 cto
.ReadIntervalTimeout
= MAXDWORD
;
2575 cto
.ReadTotalTimeoutMultiplier
= MAXDWORD
;
2576 cto
.ReadTotalTimeoutConstant
= 1; /* wait no more than 1 ms */
2577 cto
.WriteTotalTimeoutMultiplier
= 0;
2578 cto
.WriteTotalTimeoutConstant
= 0;
2580 if (!SetCommTimeouts (h
, &cto
)
2581 #ifdef USE_BIG_SERIAL_BUFFERS
2582 || !SetupComm (h
, 65536, 65536))
2586 e
= err_code_from_GetLastError ();
2591 return ___device_stream_setup
2595 ___DIRECTION_RD
|___DIRECTION_WR
);
2601 /*---------------------------------------------------------------------------*/
2603 /* Pipe stream device */
2606 * Pipes may be unidirectional or bidirectional. Bidirectional pipes
2607 * are implemented with 2 OS pipes: a "write" pipe and a "read" pipe.
2610 typedef struct ___device_pipe_struct
2612 ___device_stream base
;
2615 int fd_wr
; /* file descriptor for "write" pipe (-1 if none) */
2616 int fd_rd
; /* file descriptor for "read" pipe (-1 if none) */
2620 HANDLE h_wr
; /* handle for "write" pipe (NULL if none) */
2621 HANDLE h_rd
; /* handle for "read" pipe (NULL if none) */
2622 int poll_interval_nsecs
; /* interval between read attempts */
2627 typedef struct ___device_pipe_vtbl_struct
2629 ___device_stream_vtbl base
;
2630 } ___device_pipe_vtbl
;
2632 ___HIDDEN
int ___device_pipe_kind
2633 ___P((___device
*self
),
2637 return ___PIPE_DEVICE_KIND
;
2640 ___SCMOBJ ___device_pipe_cleanup
2641 ___P((___device_pipe
*dev
),
2643 ___device_pipe
*dev
;)
2645 return ___FIX(___NO_ERR
);
2649 ___HIDDEN ___SCMOBJ ___device_pipe_close_raw_virt
2650 ___P((___device_stream
*self
,
2654 ___device_stream
*self
;
2657 ___device_pipe
*d
= ___CAST(___device_pipe
*,self
);
2658 int is_not_closed
= 0;
2660 if (d
->base
.base
.read_stage
!= ___STAGE_CLOSED
)
2661 is_not_closed
|= ___DIRECTION_RD
;
2663 if (d
->base
.base
.write_stage
!= ___STAGE_CLOSED
)
2664 is_not_closed
|= ___DIRECTION_WR
;
2666 if (is_not_closed
== 0)
2667 return ___FIX(___NO_ERR
);
2669 if (is_not_closed
& direction
& ___DIRECTION_RD
)
2671 /* Close "read" pipe */
2673 d
->base
.base
.read_stage
= ___STAGE_CLOSED
;
2675 if ((d
->base
.base
.close_direction
& ___DIRECTION_RD
)
2679 if (d
->fd_rd
>= 0 &&
2680 d
->fd_rd
!= d
->fd_wr
&&
2681 close_no_EINTR (d
->fd_rd
) < 0)
2682 return err_code_from_errno ();
2686 if (d
->h_rd
!= NULL
&&
2688 CloseHandle (d
->h_rd
); /* ignore error */
2693 if (is_not_closed
& direction
& ___DIRECTION_WR
)
2695 /* Close "write" pipe */
2697 d
->base
.base
.write_stage
= ___STAGE_CLOSED
;
2699 if ((d
->base
.base
.close_direction
& ___DIRECTION_WR
)
2703 if (d
->fd_wr
>= 0 &&
2704 close_no_EINTR (d
->fd_wr
) < 0)
2705 return err_code_from_errno ();
2709 if (d
->h_wr
!= NULL
)
2710 CloseHandle (d
->h_wr
); /* ignore error */
2715 return ___FIX(___NO_ERR
);
2718 ___HIDDEN ___SCMOBJ ___device_pipe_select_raw_virt
2719 ___P((___device_stream
*self
,
2720 ___BOOL for_writing
,
2723 ___device_select_state
*state
),
2729 ___device_stream
*self
;
2730 ___BOOL for_writing
;
2733 ___device_select_state
*state
;)
2735 ___device_pipe
*d
= ___CAST(___device_pipe
*,self
);
2736 int stage
= (for_writing
2737 ? d
->base
.base
.write_stage
2738 : d
->base
.base
.read_stage
);
2740 if (pass
== ___SELECT_PASS_1
)
2742 if (stage
!= ___STAGE_OPEN
)
2743 state
->timeout
= ___time_mod
.time_neg_infinity
;
2750 ___device_select_add_fd (state
, d
->fd_wr
, 1);
2755 ___device_select_add_fd (state
, d
->fd_rd
, 0);
2762 if (d
->h_wr
!= NULL
)
2763 ___device_select_add_wait_obj (state
, i
, d
->h_wr
);
2767 if (d
->h_rd
!= NULL
)
2769 int interval
= d
->poll_interval_nsecs
* 6 / 5;
2770 if (interval
< 1000000)
2771 interval
= 1000000; /* min interval = 0.001 secs */
2772 else if (interval
> 200000000)
2773 interval
= 200000000; /* max interval = 0.2 sec */
2774 d
->poll_interval_nsecs
= interval
;
2775 ___device_select_add_relative_timeout (state
, i
, interval
* 1e-9);
2780 return ___FIX(___SELECT_SETUP_DONE
);
2783 /* pass == ___SELECT_PASS_CHECK */
2785 if (stage
!= ___STAGE_OPEN
)
2786 state
->devs
[i
] = NULL
;
2793 if (d
->fd_wr
< 0 || FD_ISSET(d
->fd_wr
, &state
->writefds
))
2794 state
->devs
[i
] = NULL
;
2798 if (d
->fd_rd
< 0 || FD_ISSET(d
->fd_rd
, &state
->readfds
))
2799 state
->devs
[i
] = NULL
;
2808 if (d
->h_wr
!= NULL
&& state
->devs_next
[i
] != -1)
2809 state
->devs
[i
] = NULL
;
2813 if (d
->h_rd
!= NULL
)
2814 state
->devs
[i
] = NULL
;
2820 return ___FIX(___NO_ERR
);
2823 ___HIDDEN ___SCMOBJ ___device_pipe_release_raw_virt
2824 ___P((___device_stream
*self
),
2826 ___device_stream
*self
;)
2828 return ___FIX(___NO_ERR
);
2831 ___HIDDEN ___SCMOBJ ___device_pipe_force_output_raw_virt
2832 ___P((___device_stream
*self
,
2836 ___device_stream
*self
;
2839 return ___FIX(___NO_ERR
);
2842 ___HIDDEN ___SCMOBJ ___device_pipe_seek_raw_virt
2843 ___P((___device_stream
*self
,
2844 ___stream_index
*pos
,
2849 ___device_stream
*self
;
2850 ___stream_index
*pos
;
2853 return ___FIX(___INVALID_OP_ERR
);
2856 ___HIDDEN ___SCMOBJ ___device_pipe_read_raw_virt
2857 ___P((___device_stream
*self
,
2859 ___stream_index len
,
2860 ___stream_index
*len_done
),
2865 ___device_stream
*self
;
2867 ___stream_index len
;
2868 ___stream_index
*len_done
;)
2870 ___device_pipe
*d
= ___CAST(___device_pipe
*,self
);
2871 ___SCMOBJ e
= ___FIX(___NO_ERR
);
2873 if (d
->base
.base
.read_stage
!= ___STAGE_OPEN
)
2874 return ___FIX(___CLOSED_DEVICE_ERR
);
2884 if ((n
= read (d
->fd_rd
, buf
, len
)) < 0)
2887 if (errno
== EIO
) errno
= EAGAIN
;
2889 if (errno
== EIO
) /* on linux, treating EIO as EAGAIN gives an infinite loop */
2893 e
= err_code_from_errno ();
2903 if (d
->h_rd
== NULL
)
2909 if (!PeekNamedPipe (d
->h_rd
, NULL
, 0, NULL
, &n
, NULL
))
2910 e
= err_code_from_GetLastError ();
2912 e
= ___ERR_CODE_EAGAIN
;
2918 if (!ReadFile (d
->h_rd
, buf
, len
, &n
, NULL
))
2919 e
= err_code_from_GetLastError ();
2921 d
->poll_interval_nsecs
= 0;
2924 if (e
== ___FIX(___WIN32_ERR(ERROR_BROKEN_PIPE
)))
2925 e
= ___FIX(___NO_ERR
); /* generate end-of-file on broken pipe */
2935 ___HIDDEN ___SCMOBJ ___device_pipe_write_raw_virt
2936 ___P((___device_stream
*self
,
2938 ___stream_index len
,
2939 ___stream_index
*len_done
),
2944 ___device_stream
*self
;
2946 ___stream_index len
;
2947 ___stream_index
*len_done
;)
2949 ___device_pipe
*d
= ___CAST(___device_pipe
*,self
);
2951 if (d
->base
.base
.write_stage
!= ___STAGE_OPEN
)
2952 return ___FIX(___CLOSED_DEVICE_ERR
);
2962 if ((n
= write (d
->fd_wr
, buf
, len
)) < 0)
2963 return err_code_from_errno ();
2972 if (d
->h_wr
== NULL
)
2978 if (!WriteFile (d
->h_wr
, buf
, len
, &n
, NULL
))
2979 return err_code_from_GetLastError ();
2986 return ___FIX(___NO_ERR
);
2989 ___HIDDEN ___SCMOBJ ___device_pipe_width_virt
2990 ___P((___device_stream
*self
),
2992 ___device_stream
*self
;)
2997 ___HIDDEN ___SCMOBJ ___device_pipe_default_options_virt
2998 ___P((___device_stream
*self
),
3000 ___device_stream
*self
;)
3002 int char_encoding_errors
= ___CHAR_ENCODING_ERRORS_ON
;
3003 int char_encoding
= ___CHAR_ENCODING_ISO_8859_1
;
3004 int eol_encoding
= ___EOL_ENCODING_LF
;
3005 int buffering
= ___FULL_BUFFERING
;
3007 return ___FIX(___STREAM_OPTIONS(char_encoding_errors
,
3011 char_encoding_errors
,
3018 ___HIDDEN ___SCMOBJ ___device_pipe_options_set_virt
3019 ___P((___device_stream
*self
,
3023 ___device_stream
*self
;
3026 return ___FIX(___NO_ERR
);
3030 ___HIDDEN ___device_pipe_vtbl ___device_pipe_table
=
3034 ___device_pipe_kind
,
3035 ___device_stream_select_virt
,
3036 ___device_stream_release_virt
,
3037 ___device_stream_force_output_virt
,
3038 ___device_stream_close_virt
3040 ___device_pipe_select_raw_virt
,
3041 ___device_pipe_release_raw_virt
,
3042 ___device_pipe_force_output_raw_virt
,
3043 ___device_pipe_close_raw_virt
,
3044 ___device_pipe_seek_raw_virt
,
3045 ___device_pipe_read_raw_virt
,
3046 ___device_pipe_write_raw_virt
,
3047 ___device_pipe_width_virt
,
3048 ___device_pipe_default_options_virt
,
3049 ___device_pipe_options_set_virt
3056 ___HIDDEN ___SCMOBJ ___device_pipe_setup_from_fd
3057 ___P((___device_pipe
**dev
,
3058 ___device_group
*dgroup
,
3067 ___device_pipe
**dev
;
3068 ___device_group
*dgroup
;
3075 d
= ___CAST(___device_pipe
*,
3076 ___alloc_mem (sizeof (___device_pipe
)));
3079 return ___FIX(___HEAP_OVERFLOW_ERR
);
3081 d
->base
.base
.vtbl
= &___device_pipe_table
;
3087 return ___device_stream_setup
3099 ___HIDDEN ___SCMOBJ ___device_pipe_setup_from_handle
3100 ___P((___device_pipe
**dev
,
3101 ___device_group
*dgroup
,
3112 ___device_pipe
**dev
;
3113 ___device_group
*dgroup
;
3121 d
= ___CAST(___device_pipe
*,
3122 ___alloc_mem (sizeof (___device_pipe
)));
3125 return ___FIX(___HEAP_OVERFLOW_ERR
);
3127 d
->base
.base
.vtbl
= &___device_pipe_table
;
3130 d
->poll_interval_nsecs
= 0;
3134 return ___device_stream_setup
3144 /*---------------------------------------------------------------------------*/
3146 /* Process stream device */
3148 typedef struct ___device_process_struct
3150 ___device_pipe base
;
3153 pid_t pid
; /* pid of the process */
3157 PROCESS_INFORMATION pi
; /* process information */
3160 int status
; /* process status */
3161 ___BOOL got_status
; /* was the status retrieved? */
3162 ___BOOL cleanuped
; /* has process been cleaned-up? */
3163 } ___device_process
;
3165 typedef struct ___device_process_vtbl_struct
3167 ___device_stream_vtbl base
;
3168 } ___device_process_vtbl
;
3170 ___HIDDEN
int ___device_process_kind
3171 ___P((___device
*self
),
3175 return ___PROCESS_DEVICE_KIND
;
3178 ___SCMOBJ ___device_process_cleanup
3179 ___P((___device_process
*dev
),
3181 ___device_process
*dev
;)
3183 if (!dev
->cleanuped
)
3192 CloseHandle (dev
->pi
.hProcess
); /* ignore error */
3193 CloseHandle (dev
->pi
.hThread
); /* ignore error */
3198 return ___FIX(___NO_ERR
);
3202 ___SCMOBJ ___device_process_status_set
3203 ___P((___device_process
*dev
,
3207 ___device_process
*dev
;
3210 ___SCMOBJ e
= ___FIX(___NO_ERR
);
3212 if (!dev
->got_status
)
3214 dev
->status
= status
;
3215 dev
->got_status
= 1;
3216 e
= ___device_process_cleanup (dev
); /* ignore error */
3223 ___SCMOBJ ___device_process_status_poll
3224 ___P((___device_process
*dev
),
3226 ___device_process
*dev
;)
3228 if (!dev
->got_status
)
3233 * The process status is updated asynchronously by
3234 * sigchld_signal_handler.
3243 if (!GetExitCodeProcess (dev
->pi
.hProcess
, &status
))
3244 return err_code_from_GetLastError ();
3246 if (status
!= STILL_ACTIVE
)
3247 ___device_process_status_set (dev
, status
<< 8); /* ignore error */
3252 return ___FIX(___NO_ERR
);
3255 ___HIDDEN ___SCMOBJ ___device_process_close_raw_virt
3256 ___P((___device_stream
*self
,
3260 ___device_stream
*self
;
3263 ___device_process
*d
= ___CAST(___device_process
*,self
);
3264 ___SCMOBJ e
= ___device_pipe_close_raw_virt (self
, direction
);
3266 if (e
== ___FIX(___NO_ERR
))
3268 if (d
->base
.base
.base
.read_stage
== ___STAGE_CLOSED
&&
3269 d
->base
.base
.base
.write_stage
== ___STAGE_CLOSED
)
3270 ___device_process_status_poll (d
); /* ignore error */
3276 ___HIDDEN ___SCMOBJ ___device_process_select_raw_virt
3277 ___P((___device_stream
*self
,
3278 ___BOOL for_writing
,
3281 ___device_select_state
*state
),
3287 ___device_stream
*self
;
3288 ___BOOL for_writing
;
3291 ___device_select_state
*state
;)
3293 return ___device_pipe_select_raw_virt (self
, for_writing
, i
, pass
, state
);
3296 ___HIDDEN ___SCMOBJ ___device_process_release_raw_virt
3297 ___P((___device_stream
*self
),
3299 ___device_stream
*self
;)
3301 ___device_process
*d
= ___CAST(___device_process
*,self
);
3302 ___SCMOBJ e1
= ___device_pipe_release_raw_virt (self
);
3303 ___SCMOBJ e2
= ___device_process_cleanup (d
);
3304 if (e1
== ___FIX(___NO_ERR
))
3309 ___HIDDEN ___SCMOBJ ___device_process_force_output_raw_virt
3310 ___P((___device_stream
*self
,
3314 ___device_stream
*self
;
3317 return ___device_pipe_force_output_raw_virt (self
, level
);
3320 ___HIDDEN ___SCMOBJ ___device_process_seek_raw_virt
3321 ___P((___device_stream
*self
,
3322 ___stream_index
*pos
,
3327 ___device_stream
*self
;
3328 ___stream_index
*pos
;
3331 return ___device_pipe_seek_raw_virt (self
, pos
, whence
);
3334 ___HIDDEN ___SCMOBJ ___device_process_read_raw_virt
3335 ___P((___device_stream
*self
,
3337 ___stream_index len
,
3338 ___stream_index
*len_done
),
3343 ___device_stream
*self
;
3345 ___stream_index len
;
3346 ___stream_index
*len_done
;)
3348 return ___device_pipe_read_raw_virt (self
, buf
, len
, len_done
);
3351 ___HIDDEN ___SCMOBJ ___device_process_write_raw_virt
3352 ___P((___device_stream
*self
,
3354 ___stream_index len
,
3355 ___stream_index
*len_done
),
3360 ___device_stream
*self
;
3362 ___stream_index len
;
3363 ___stream_index
*len_done
;)
3365 return ___device_pipe_write_raw_virt (self
, buf
, len
, len_done
);
3368 ___HIDDEN ___SCMOBJ ___device_process_width_virt
3369 ___P((___device_stream
*self
),
3371 ___device_stream
*self
;)
3376 ___HIDDEN ___SCMOBJ ___device_process_default_options_virt
3377 ___P((___device_stream
*self
),
3379 ___device_stream
*self
;)
3381 return ___device_pipe_default_options_virt (self
);
3385 ___HIDDEN ___SCMOBJ ___device_process_options_set_virt
3386 ___P((___device_stream
*self
,
3390 ___device_stream
*self
;
3393 return ___device_pipe_options_set_virt (self
, options
);
3397 ___HIDDEN ___device_process_vtbl ___device_process_table
=
3401 ___device_process_kind
,
3402 ___device_stream_select_virt
,
3403 ___device_stream_release_virt
,
3404 ___device_stream_force_output_virt
,
3405 ___device_stream_close_virt
3407 ___device_process_select_raw_virt
,
3408 ___device_process_release_raw_virt
,
3409 ___device_process_force_output_raw_virt
,
3410 ___device_process_close_raw_virt
,
3411 ___device_process_seek_raw_virt
,
3412 ___device_process_read_raw_virt
,
3413 ___device_process_write_raw_virt
,
3414 ___device_process_width_virt
,
3415 ___device_process_default_options_virt
,
3416 ___device_process_options_set_virt
3422 ___SCMOBJ ___device_process_setup_from_pid
3423 ___P((___device_process
**dev
,
3424 ___device_group
*dgroup
,
3435 ___device_process
**dev
;
3436 ___device_group
*dgroup
;
3442 ___device_process
*d
;
3444 d
= ___CAST(___device_process
*,
3445 ___alloc_mem (sizeof (___device_process
)));
3448 return ___FIX(___HEAP_OVERFLOW_ERR
);
3451 * Setup file descriptors to perform nonblocking I/O.
3454 if ((fd_stdout
>= 0 &&
3455 (direction
& ___DIRECTION_RD
) &&
3456 (set_fd_blocking_mode (fd_stdout
, 0) < 0)) ||
3458 (direction
& ___DIRECTION_WR
) &&
3459 (set_fd_blocking_mode (fd_stdin
, 0) < 0)))
3461 ___SCMOBJ e
= err_code_from_errno ();
3466 d
->base
.base
.base
.vtbl
= &___device_process_table
;
3467 d
->base
.fd_rd
= fd_stdout
;
3468 d
->base
.fd_wr
= fd_stdin
;
3476 return ___device_stream_setup
3487 ___SCMOBJ ___device_process_setup_from_process
3488 ___P((___device_process
**dev
,
3489 ___device_group
*dgroup
,
3490 PROCESS_INFORMATION pi
,
3500 ___device_process
**dev
;
3501 ___device_group
*dgroup
;
3502 PROCESS_INFORMATION pi
;
3507 ___device_process
*d
;
3509 d
= ___CAST(___device_process
*,
3510 ___alloc_mem (sizeof (___device_process
)));
3513 return ___FIX(___HEAP_OVERFLOW_ERR
);
3515 d
->base
.base
.base
.vtbl
= &___device_process_table
;
3516 d
->base
.h_rd
= hstdout
;
3517 d
->base
.h_wr
= hstdin
;
3525 return ___device_stream_setup
3535 /*---------------------------------------------------------------------------*/
3537 #ifdef USE_NETWORKING
3539 /* Socket utilities */
3542 #define SOCKET_TYPE int
3543 #define SOCKET_CALL_ERROR(s) ((s) < 0)
3544 #define SOCKET_CALL_ERROR2(s) ((s) < 0)
3545 #define CONNECT_IN_PROGRESS (errno == EINPROGRESS)
3546 #define CONNECT_WOULD_BLOCK (errno == EAGAIN)
3547 #define NOT_CONNECTED(e) ((e) == ___FIX(___ERRNO_ERR(ENOTCONN)))
3548 #define CLOSE_SOCKET(s) close_no_EINTR (s)
3549 #define ERR_CODE_FROM_SOCKET_CALL err_code_from_errno ()
3550 #define IOCTL_SOCKET(s,cmd,argp) ioctl (s,cmd,argp)
3551 #define SOCKET_LEN_TYPE socklen_t
3555 #define SOCKET_TYPE SOCKET
3556 #define SOCKET_CALL_ERROR(s) ((s) == SOCKET_ERROR)
3557 #define SOCKET_CALL_ERROR2(s) ((s) == INVALID_SOCKET)
3558 #define CONNECT_IN_PROGRESS ((WSAGetLastError () == WSAEALREADY) || \
3559 (WSAGetLastError () == WSAEISCONN))
3560 #define CONNECT_WOULD_BLOCK ((WSAGetLastError () == WSAEWOULDBLOCK) || \
3561 (WSAGetLastError () == WSAEINVAL))
3562 #define NOT_CONNECTED(e) ((e) == ___FIX(___WIN32_ERR(WSAENOTCONN)))
3563 #define CLOSE_SOCKET(s) closesocket (s)
3564 #define ERR_CODE_FROM_SOCKET_CALL err_code_from_WSAGetLastError ()
3565 #define IOCTL_SOCKET(s,cmd,argp) ioctlsocket (s,cmd,argp)
3566 #define SOCKET_LEN_TYPE int
3570 #define SHUTDOWN_RD SHUT_RD
3573 #define SHUTDOWN_RD SD_RECEIVE
3575 #define SHUTDOWN_RD 0
3580 #define SHUTDOWN_WR SHUT_WR
3583 #define SHUTDOWN_WR SD_SEND
3585 #define SHUTDOWN_WR 1
3592 /*---------------------------------------------------------------------------*/
3594 #ifdef USE_NETWORKING
3596 /* TCP client stream device */
3598 typedef struct ___device_tcp_client_struct
3600 ___device_stream base
;
3602 struct sockaddr server_addr
;
3603 SOCKET_LEN_TYPE server_addrlen
;
3604 int try_connect_again
;
3609 int try_connect_interval_nsecs
;
3615 long io_events
; /* used by ___device_tcp_client_select_raw_virt */
3616 HANDLE io_event
; /* used by ___device_tcp_client_select_raw_virt */
3619 } ___device_tcp_client
;
3622 typedef struct ___device_tcp_client_vtbl_struct
3624 ___device_stream_vtbl base
;
3625 } ___device_tcp_client_vtbl
;
3628 ___HIDDEN
int try_connect
3629 ___P((___device_tcp_client
*dev
),
3631 ___device_tcp_client
*dev
;)
3633 if (!SOCKET_CALL_ERROR(connect (dev
->s
,
3635 dev
->server_addrlen
)) ||
3636 CONNECT_IN_PROGRESS
|| /* establishing connection in background */
3637 dev
->try_connect_again
== 2) /* last connect attempt? */
3639 dev
->try_connect_again
= 0; /* we're done waiting */
3643 if (CONNECT_WOULD_BLOCK
) /* connect can't be performed now */
3649 ___HIDDEN
int ___device_tcp_client_kind
3650 ___P((___device
*self
),
3654 return ___TCP_CLIENT_DEVICE_KIND
;
3658 ___HIDDEN ___SCMOBJ ___device_tcp_client_close_raw_virt
3659 ___P((___device_stream
*self
,
3663 ___device_stream
*self
;
3666 ___device_tcp_client
*d
= ___CAST(___device_tcp_client
*,self
);
3667 int is_not_closed
= 0;
3669 if (d
->base
.base
.read_stage
!= ___STAGE_CLOSED
)
3670 is_not_closed
|= ___DIRECTION_RD
;
3672 if (d
->base
.base
.write_stage
!= ___STAGE_CLOSED
)
3673 is_not_closed
|= ___DIRECTION_WR
;
3675 if (is_not_closed
== 0)
3676 return ___FIX(___NO_ERR
);
3678 if ((is_not_closed
& ~direction
) == 0)
3680 /* Close socket when both sides are closed. */
3682 d
->base
.base
.read_stage
= ___STAGE_CLOSED
; /* avoid multiple closes */
3683 d
->base
.base
.write_stage
= ___STAGE_CLOSED
;
3687 if (d
->io_event
!= NULL
)
3688 CloseHandle (d
->io_event
); /* ignore error */
3692 if ((d
->base
.base
.close_direction
& (___DIRECTION_RD
|___DIRECTION_WR
))
3693 == (___DIRECTION_RD
|___DIRECTION_WR
))
3695 if (CLOSE_SOCKET(d
->s
) != 0)
3696 return ERR_CODE_FROM_SOCKET_CALL
;
3699 else if (is_not_closed
& direction
& ___DIRECTION_RD
)
3701 /* Shutdown receiving side. */
3703 if ((d
->base
.base
.close_direction
& ___DIRECTION_RD
)
3706 if (shutdown (d
->s
, SHUTDOWN_RD
) != 0)
3708 ___SCMOBJ e
= ERR_CODE_FROM_SOCKET_CALL
;
3709 if (!NOT_CONNECTED(e
))
3714 d
->base
.base
.read_stage
= ___STAGE_CLOSED
;
3716 else if (is_not_closed
& direction
& ___DIRECTION_WR
)
3718 /* Shutdown sending side. */
3720 if ((d
->base
.base
.close_direction
& ___DIRECTION_WR
)
3723 if (shutdown (d
->s
, SHUTDOWN_WR
) != 0)
3725 ___SCMOBJ e
= ERR_CODE_FROM_SOCKET_CALL
;
3726 if (!NOT_CONNECTED(e
))
3731 d
->base
.base
.write_stage
= ___STAGE_CLOSED
;
3734 return ___FIX(___NO_ERR
);
3737 ___HIDDEN ___SCMOBJ ___device_tcp_client_select_raw_virt
3738 ___P((___device_stream
*self
,
3739 ___BOOL for_writing
,
3742 ___device_select_state
*state
),
3748 ___device_stream
*self
;
3749 ___BOOL for_writing
;
3752 ___device_select_state
*state
;)
3754 ___device_tcp_client
*d
= ___CAST(___device_tcp_client
*,self
);
3755 int stage
= (for_writing
3756 ? d
->base
.base
.write_stage
3757 : d
->base
.base
.read_stage
);
3759 if (pass
== ___SELECT_PASS_1
)
3761 if (stage
!= ___STAGE_OPEN
)
3763 state
->timeout
= ___time_mod
.time_neg_infinity
;
3764 return ___FIX(___SELECT_SETUP_DONE
);
3770 if (d
->try_connect_again
!= 0)
3772 int interval
= d
->try_connect_interval_nsecs
* 6 / 5;
3773 if (interval
> 200000000) /* max interval = 0.2 sec */
3774 interval
= 200000000;
3775 d
->try_connect_interval_nsecs
= interval
;
3776 ___device_select_add_relative_timeout (state
, i
, interval
* 1e-9);
3779 ___device_select_add_fd (state
, d
->s
, for_writing
);
3781 return ___FIX(___SELECT_SETUP_DONE
);
3789 return ___FIX(___NO_ERR
);
3797 else if (pass
== ___SELECT_PASS_2
)
3799 if (d
->try_connect_again
!= 0)
3800 d
->io_events
= (FD_CONNECT
| FD_CLOSE
);
3801 else if (for_writing
)
3802 d
->io_events
|= (FD_WRITE
| FD_CLOSE
);
3804 d
->io_events
|= (FD_READ
| FD_CLOSE
);
3806 return ___FIX(___NO_ERR
);
3808 else if (pass
== ___SELECT_PASS_3
)
3810 HANDLE wait_obj
= d
->io_event
;
3812 ResetEvent (wait_obj
); /* ignore error */
3814 WSAEventSelect (d
->s
, wait_obj
, d
->io_events
);
3816 ___device_select_add_wait_obj (state
, i
, wait_obj
);
3818 return ___FIX(___SELECT_SETUP_DONE
);
3823 /* pass == ___SELECT_PASS_CHECK */
3825 if (stage
!= ___STAGE_OPEN
)
3826 state
->devs
[i
] = NULL
;
3831 if (d
->try_connect_again
!= 0 ||
3833 ? FD_ISSET(d
->s
, &state
->writefds
)
3834 : FD_ISSET(d
->s
, &state
->readfds
)))
3836 d
->connect_done
= 1;
3837 state
->devs
[i
] = NULL
;
3844 if (state
->devs_next
[i
] != -1)
3846 state
->devs
[i
] = NULL
;
3847 if (d
->try_connect_again
!= 0)
3849 d
->connect_done
= 1;
3850 d
->try_connect_again
= 2;
3857 return ___FIX(___NO_ERR
);
3860 ___HIDDEN ___SCMOBJ ___device_tcp_client_release_raw_virt
3861 ___P((___device_stream
*self
),
3863 ___device_stream
*self
;)
3865 return ___FIX(___NO_ERR
);
3868 ___HIDDEN ___SCMOBJ ___device_tcp_client_force_output_raw_virt
3869 ___P((___device_stream
*self
,
3873 ___device_stream
*self
;
3876 return ___FIX(___NO_ERR
);
3879 ___HIDDEN ___SCMOBJ ___device_tcp_client_seek_raw_virt
3880 ___P((___device_stream
*self
,
3881 ___stream_index
*pos
,
3886 ___device_stream
*self
;
3887 ___stream_index
*pos
;
3890 return ___FIX(___INVALID_OP_ERR
);
3893 ___HIDDEN ___SCMOBJ ___device_tcp_client_read_raw_virt
3894 ___P((___device_stream
*self
,
3896 ___stream_index len
,
3897 ___stream_index
*len_done
),
3902 ___device_stream
*self
;
3904 ___stream_index len
;
3905 ___stream_index
*len_done
;)
3907 ___device_tcp_client
*d
= ___CAST(___device_tcp_client
*,self
);
3910 if (d
->base
.base
.read_stage
!= ___STAGE_OPEN
)
3911 return ___FIX(___CLOSED_DEVICE_ERR
);
3913 if (d
->try_connect_again
!= 0)
3915 if (try_connect (d
) == 0)
3917 if (d
->try_connect_again
!= 0)
3918 return ___ERR_CODE_EAGAIN
;
3921 return ERR_CODE_FROM_SOCKET_CALL
;
3924 if (SOCKET_CALL_ERROR(n
= recv (d
->s
, ___CAST(char*,buf
), len
, 0)))
3926 ___SCMOBJ e
= ERR_CODE_FROM_SOCKET_CALL
;
3927 if (NOT_CONNECTED(e
) && !d
->connect_done
)
3928 e
= ___ERR_CODE_EAGAIN
;
3934 return ___FIX(___NO_ERR
);
3938 ___HIDDEN ___SCMOBJ ___device_tcp_client_write_raw_virt
3939 ___P((___device_stream
*self
,
3941 ___stream_index len
,
3942 ___stream_index
*len_done
),
3947 ___device_stream
*self
;
3949 ___stream_index len
;
3950 ___stream_index
*len_done
;)
3952 ___device_tcp_client
*d
= ___CAST(___device_tcp_client
*,self
);
3955 if (d
->base
.base
.write_stage
!= ___STAGE_OPEN
)
3956 return ___FIX(___CLOSED_DEVICE_ERR
);
3958 if (d
->try_connect_again
!= 0)
3960 if (try_connect (d
) == 0)
3962 if (d
->try_connect_again
!= 0)
3963 return ___ERR_CODE_EAGAIN
;
3966 return ERR_CODE_FROM_SOCKET_CALL
;
3969 if (SOCKET_CALL_ERROR(n
= send (d
->s
, ___CAST(char*,buf
), len
, 0)))
3971 ___SCMOBJ e
= ERR_CODE_FROM_SOCKET_CALL
;
3972 if (NOT_CONNECTED(e
) && !d
->connect_done
)
3973 e
= ___ERR_CODE_EAGAIN
;
3979 return ___FIX(___NO_ERR
);
3983 ___HIDDEN ___SCMOBJ ___device_tcp_client_width_virt
3984 ___P((___device_stream
*self
),
3986 ___device_stream
*self
;)
3992 ___HIDDEN ___SCMOBJ ___device_tcp_client_default_options_virt
3993 ___P((___device_stream
*self
),
3995 ___device_stream
*self
;)
3997 int char_encoding_errors
= ___CHAR_ENCODING_ERRORS_ON
;
3998 int char_encoding
= ___CHAR_ENCODING_ISO_8859_1
;
3999 int eol_encoding
= ___EOL_ENCODING_LF
;
4000 int buffering
= ___FULL_BUFFERING
;
4002 return ___FIX(___STREAM_OPTIONS(char_encoding_errors
,
4006 char_encoding_errors
,
4013 ___HIDDEN ___SCMOBJ ___device_tcp_client_options_set_virt
4014 ___P((___device_stream
*self
,
4018 ___device_stream
*self
;
4021 return ___FIX(___NO_ERR
);
4025 ___HIDDEN ___device_tcp_client_vtbl ___device_tcp_client_table
=
4029 ___device_tcp_client_kind
,
4030 ___device_stream_select_virt
,
4031 ___device_stream_release_virt
,
4032 ___device_stream_force_output_virt
,
4033 ___device_stream_close_virt
4035 ___device_tcp_client_select_raw_virt
,
4036 ___device_tcp_client_release_raw_virt
,
4037 ___device_tcp_client_force_output_raw_virt
,
4038 ___device_tcp_client_close_raw_virt
,
4039 ___device_tcp_client_seek_raw_virt
,
4040 ___device_tcp_client_read_raw_virt
,
4041 ___device_tcp_client_write_raw_virt
,
4042 ___device_tcp_client_width_virt
,
4043 ___device_tcp_client_default_options_virt
,
4044 ___device_tcp_client_options_set_virt
4049 #define ___SOCK_KEEPALIVE_FLAG(options) (((options) & 1) != 0)
4050 #define ___SOCK_NO_COALESCE_FLAG(options) (((options) & 2) != 0)
4051 #define ___SOCK_REUSE_ADDRESS_FLAG(options) (((options) & 2048) != 0)
4054 ___HIDDEN ___SCMOBJ create_tcp_socket
4055 ___P((SOCKET_TYPE
*sock
,
4062 int keepalive_flag
= ___SOCK_KEEPALIVE_FLAG(options
);
4063 int no_coalesce_flag
= ___SOCK_NO_COALESCE_FLAG(options
);
4064 int reuse_address_flag
= ___SOCK_REUSE_ADDRESS_FLAG(options
);
4067 if (SOCKET_CALL_ERROR2(s
= socket (AF_INET
, SOCK_STREAM
, 0)))
4068 return ERR_CODE_FROM_SOCKET_CALL
;
4071 #define TCP_NODELAY 1
4074 if ((keepalive_flag
!= 0 &&
4075 setsockopt (s
, /* keep connection alive or not */
4078 ___CAST(char*,&keepalive_flag
),
4079 sizeof (keepalive_flag
)) != 0) ||
4080 (reuse_address_flag
!= 0 &&
4081 setsockopt (s
, /* allow reusing the same address */
4084 ___CAST(char*,&reuse_address_flag
),
4085 sizeof (reuse_address_flag
)) != 0) ||
4086 (no_coalesce_flag
!= 0 &&
4087 setsockopt (s
, /* enable or disable packet coalescing algorithm */
4090 ___CAST(char*,&no_coalesce_flag
),
4091 sizeof (no_coalesce_flag
)) != 0))
4093 ___SCMOBJ e
= ERR_CODE_FROM_SOCKET_CALL
;
4094 CLOSE_SOCKET(s
); /* ignore error */
4100 return ___FIX(___NO_ERR
);
4104 ___HIDDEN
int set_socket_non_blocking
4105 ___P((SOCKET_TYPE s
),
4115 unsigned long param
= 1;
4117 return SOCKET_CALL_ERROR(IOCTL_SOCKET(s
, FIONBIO
, ¶m
));
4121 return set_fd_blocking_mode (s
, 0);
4127 ___SCMOBJ ___device_tcp_client_setup_from_socket
4128 ___P((___device_tcp_client
**dev
,
4129 ___device_group
*dgroup
,
4131 struct sockaddr
*server_addr
,
4132 SOCKET_LEN_TYPE server_addrlen
,
4133 int try_connect_again
,
4142 ___device_tcp_client
**dev
;
4143 ___device_group
*dgroup
;
4145 struct sockaddr
*server_addr
;
4146 SOCKET_LEN_TYPE server_addrlen
;
4147 int try_connect_again
;
4151 ___device_tcp_client
*d
;
4153 d
= ___CAST(___device_tcp_client
*,
4154 ___alloc_mem (sizeof (___device_tcp_client
)));
4157 return ___FIX(___HEAP_OVERFLOW_ERR
);
4160 * Setup socket to perform nonblocking I/O.
4163 if (set_socket_non_blocking (s
) != 0) /* set nonblocking mode */
4165 e
= ERR_CODE_FROM_SOCKET_CALL
;
4170 d
->base
.base
.vtbl
= &___device_tcp_client_table
;
4172 d
->server_addr
= *server_addr
;
4173 d
->server_addrlen
= server_addrlen
;
4174 d
->try_connect_again
= try_connect_again
;
4175 d
->connect_done
= 0;
4179 d
->try_connect_interval_nsecs
= 1000000; /* 0.001 secs */
4186 CreateEvent (NULL
, /* can't inherit */
4187 TRUE
, /* manual reset */
4188 FALSE
, /* not signaled */
4189 NULL
); /* no name */
4191 if (d
->io_event
== NULL
)
4193 e
= err_code_from_GetLastError ();
4202 return ___device_stream_setup
4210 ___SCMOBJ ___device_tcp_client_setup_from_sockaddr
4211 ___P((___device_tcp_client
**dev
,
4212 ___device_group
*dgroup
,
4213 struct sockaddr
*server_addr
,
4214 SOCKET_LEN_TYPE server_addrlen
,
4223 ___device_tcp_client
**dev
;
4224 ___device_group
*dgroup
;
4225 struct sockaddr
*server_addr
;
4226 SOCKET_LEN_TYPE server_addrlen
;
4232 ___device_tcp_client
*d
;
4234 if ((e
= create_tcp_socket (&s
, options
)) != ___FIX(___NO_ERR
))
4237 if ((e
= ___device_tcp_client_setup_from_socket
4245 != ___FIX(___NO_ERR
))
4247 CLOSE_SOCKET(s
); /* ignore error */
4251 device_transfer_close_responsibility (___CAST(___device
*,d
));
4255 if (try_connect (d
) != 0)
4257 e
= ERR_CODE_FROM_SOCKET_CALL
;
4258 ___device_cleanup (&d
->base
.base
); /* ignore error */
4262 return ___FIX(___NO_ERR
);
4268 /*---------------------------------------------------------------------------*/
4270 #ifdef USE_NETWORKING
4272 /* TCP server device. */
4274 typedef struct ___device_tcp_server_struct
4281 HANDLE io_event
; /* used by ___device_tcp_server_select_raw_virt */
4284 } ___device_tcp_server
;
4286 typedef struct ___device_tcp_server_vtbl_struct
4288 ___device_vtbl base
;
4289 } ___device_tcp_server_vtbl
;
4291 ___HIDDEN
int ___device_tcp_server_kind
4292 ___P((___device
*self
),
4296 return ___TCP_SERVER_DEVICE_KIND
;
4299 ___HIDDEN ___SCMOBJ ___device_tcp_server_close_virt
4300 ___P((___device
*self
,
4307 ___device_tcp_server
*d
= ___CAST(___device_tcp_server
*,self
);
4309 if (d
->base
.read_stage
== ___STAGE_CLOSED
)
4310 return ___FIX(___NO_ERR
);
4312 if (direction
& ___DIRECTION_RD
)
4314 d
->base
.read_stage
= ___STAGE_CLOSED
; /* avoid multiple closes */
4318 if (d
->io_event
!= NULL
)
4319 CloseHandle (d
->io_event
); /* ignore error */
4323 if ((d
->base
.close_direction
& ___DIRECTION_RD
)
4326 if (CLOSE_SOCKET(d
->s
) != 0)
4327 return ERR_CODE_FROM_SOCKET_CALL
;
4331 return ___FIX(___NO_ERR
);
4334 ___HIDDEN ___SCMOBJ ___device_tcp_server_select_virt
4335 ___P((___device
*self
,
4336 ___BOOL for_writing
,
4339 ___device_select_state
*state
),
4346 ___BOOL for_writing
;
4349 ___device_select_state
*state
;)
4351 ___device_tcp_server
*d
= ___CAST(___device_tcp_server
*,self
);
4352 int stage
= (for_writing
4353 ? d
->base
.write_stage
4354 : d
->base
.read_stage
);
4356 if (pass
== ___SELECT_PASS_1
)
4358 if (stage
!= ___STAGE_OPEN
)
4359 state
->timeout
= ___time_mod
.time_neg_infinity
;
4363 ___device_select_add_fd (state
, d
->s
, for_writing
);
4368 HANDLE wait_obj
= d
->io_event
;
4370 ResetEvent (wait_obj
); /* ignore error */
4372 WSAEventSelect (d
->s
, wait_obj
, FD_ACCEPT
);
4374 ___device_select_add_wait_obj (state
, i
, wait_obj
);
4379 return ___FIX(___SELECT_SETUP_DONE
);
4382 /* pass == ___SELECT_PASS_CHECK */
4384 if (stage
!= ___STAGE_OPEN
)
4385 state
->devs
[i
] = NULL
;
4390 if (FD_ISSET(d
->s
, &state
->readfds
))
4391 state
->devs
[i
] = NULL
;
4397 if (state
->devs_next
[i
] != -1)
4398 state
->devs
[i
] = NULL
;
4403 return ___FIX(___NO_ERR
);
4406 ___HIDDEN ___SCMOBJ ___device_tcp_server_release_virt
4407 ___P((___device
*self
),
4411 return ___FIX(___NO_ERR
);
4414 ___HIDDEN ___SCMOBJ ___device_tcp_server_force_output_virt
4415 ___P((___device
*self
,
4422 return ___FIX(___NO_ERR
);
4425 ___HIDDEN ___device_tcp_server_vtbl ___device_tcp_server_table
=
4428 ___device_tcp_server_kind
,
4429 ___device_tcp_server_select_virt
,
4430 ___device_tcp_server_release_virt
,
4431 ___device_tcp_server_force_output_virt
,
4432 ___device_tcp_server_close_virt
4437 ___SCMOBJ ___device_tcp_server_setup
4438 ___P((___device_tcp_server
**dev
,
4439 ___device_group
*dgroup
,
4440 struct sockaddr
*server_addr
,
4441 SOCKET_LEN_TYPE server_addrlen
,
4450 ___device_tcp_server
**dev
;
4451 ___device_group
*dgroup
;
4452 struct sockaddr
*server_addr
;
4453 SOCKET_LEN_TYPE server_addrlen
;
4459 ___device_tcp_server
*d
;
4461 if ((e
= create_tcp_socket (&s
, options
)) != ___FIX(___NO_ERR
))
4464 if (set_socket_non_blocking (s
) != 0 || /* set nonblocking mode */
4465 bind (s
, server_addr
, server_addrlen
) != 0 ||
4466 listen (s
, backlog
) != 0)
4468 e
= ERR_CODE_FROM_SOCKET_CALL
;
4469 CLOSE_SOCKET(s
); /* ignore error */
4473 d
= ___CAST(___device_tcp_server
*,
4474 ___alloc_mem (sizeof (___device_tcp_server
)));
4478 CLOSE_SOCKET(s
); /* ignore error */
4479 return ___FIX(___HEAP_OVERFLOW_ERR
);
4482 d
->base
.vtbl
= &___device_tcp_server_table
;
4483 d
->base
.refcount
= 1;
4484 d
->base
.direction
= ___DIRECTION_RD
;
4485 d
->base
.close_direction
= 0; /* prevent closing on errors */
4486 d
->base
.read_stage
= ___STAGE_OPEN
;
4487 d
->base
.write_stage
= ___STAGE_CLOSED
;
4492 CreateEvent (NULL
, /* can't inherit */
4493 TRUE
, /* manual reset */
4494 FALSE
, /* not signaled */
4495 NULL
); /* no name */
4497 if (d
->io_event
== NULL
)
4499 ___SCMOBJ e
= err_code_from_GetLastError ();
4500 CLOSE_SOCKET(s
); /* ignore error */
4509 device_transfer_close_responsibility (___CAST(___device
*,d
));
4513 ___device_add_to_group (dgroup
, &d
->base
);
4515 return ___FIX(___NO_ERR
);
4519 ___SCMOBJ ___device_tcp_server_read
4520 ___P((___device_tcp_server
*dev
,
4521 ___device_group
*dgroup
,
4522 ___device_tcp_client
**client
),
4526 ___device_tcp_server
*dev
;
4527 ___device_group
*dgroup
;
4528 ___device_tcp_client
**client
;)
4531 struct sockaddr_in addr
;
4532 SOCKET_LEN_TYPE addrlen
;
4535 if (dev
->base
.read_stage
!= ___STAGE_OPEN
)
4536 return ___FIX(___CLOSED_DEVICE_ERR
);
4538 addrlen
= sizeof (addr
);
4540 if (SOCKET_CALL_ERROR2(s
= accept (dev
->s
,
4541 ___CAST(struct sockaddr
*,&addr
),
4543 return ERR_CODE_FROM_SOCKET_CALL
;
4545 if ((e
= ___device_tcp_client_setup_from_socket
4549 ___CAST(struct sockaddr
*,&addr
),
4552 ___DIRECTION_RD
|___DIRECTION_WR
))
4553 != ___FIX(___NO_ERR
))
4555 CLOSE_SOCKET(s
); /* ignore error */
4559 device_transfer_close_responsibility (___CAST(___device
*,*client
));
4561 return ___FIX(___NO_ERR
);
4567 /*---------------------------------------------------------------------------*/
4569 /* Directory device. */
4571 typedef struct ___device_directory_struct
4581 #ifdef USE_FindFirstFile
4583 WIN32_FIND_DATA fdata
;
4586 } ___device_directory
;
4588 typedef struct ___device_directory_vtbl_struct
4590 ___device_vtbl base
;
4591 } ___device_directory_vtbl
;
4593 ___HIDDEN
int ___device_directory_kind
4594 ___P((___device
*self
),
4598 return ___DIRECTORY_KIND
;
4601 ___HIDDEN ___SCMOBJ ___device_directory_close_virt
4602 ___P((___device
*self
,
4609 ___device_directory
*d
= ___CAST(___device_directory
*,self
);
4611 if (d
->base
.read_stage
== ___STAGE_CLOSED
)
4612 return ___FIX(___NO_ERR
);
4614 if (direction
& ___DIRECTION_RD
)
4616 d
->base
.read_stage
= ___STAGE_CLOSED
; /* avoid multiple closes */
4618 if ((d
->base
.close_direction
& ___DIRECTION_RD
)
4623 if (closedir (d
->dir
) < 0)
4624 return err_code_from_errno ();
4627 #ifdef USE_FindFirstFile
4628 if (!FindClose (d
->h
))
4629 return err_code_from_GetLastError ();
4634 return ___FIX(___NO_ERR
);
4637 ___HIDDEN ___SCMOBJ ___device_directory_select_virt
4638 ___P((___device
*self
,
4639 ___BOOL for_writing
,
4642 ___device_select_state
*state
),
4649 ___BOOL for_writing
;
4652 ___device_select_state
*state
;)
4654 if (pass
== ___SELECT_PASS_1
)
4656 state
->timeout
= ___time_mod
.time_neg_infinity
;
4657 return ___FIX(___SELECT_SETUP_DONE
);
4660 /* pass == ___SELECT_PASS_CHECK */
4662 state
->devs
[i
] = NULL
;
4664 return ___FIX(___NO_ERR
);
4667 ___HIDDEN ___SCMOBJ ___device_directory_release_virt
4668 ___P((___device
*self
),
4672 return ___FIX(___NO_ERR
);
4675 ___HIDDEN ___SCMOBJ ___device_directory_force_output_virt
4676 ___P((___device
*self
,
4683 return ___FIX(___NO_ERR
);
4686 ___HIDDEN ___device_directory_vtbl ___device_directory_table
=
4689 ___device_directory_kind
,
4690 ___device_directory_select_virt
,
4691 ___device_directory_release_virt
,
4692 ___device_directory_force_output_virt
,
4693 ___device_directory_close_virt
4699 #define ___DIR_OPEN_PATH_CE_SELECT(latin1,utf8,ucs2,ucs4,wchar,native) native
4702 #ifdef USE_FindFirstFile
4704 #define ___DIR_OPEN_PATH_CE_SELECT(latin1,utf8,ucs2,ucs4,wchar,native) ucs2
4706 #define ___DIR_OPEN_PATH_CE_SELECT(latin1,utf8,ucs2,ucs4,wchar,native) native
4711 #ifdef ___DIR_OPEN_PATH_CE_SELECT
4713 ___SCMOBJ ___device_directory_setup
4714 ___P((___device_directory
**dev
,
4715 ___device_group
*dgroup
,
4716 ___STRING_TYPE(___DIR_OPEN_PATH_CE_SELECT
) path
,
4722 ___device_directory
**dev
;
4723 ___device_group
*dgroup
;
4724 ___STRING_TYPE(___DIR_OPEN_PATH_CE_SELECT
) path
;
4727 ___device_directory
*d
;
4729 d
= ___CAST(___device_directory
*,
4730 ___alloc_mem (sizeof (___device_directory
)));
4733 return ___FIX(___HEAP_OVERFLOW_ERR
);
4735 d
->base
.vtbl
= &___device_directory_table
;
4736 d
->base
.refcount
= 1;
4737 d
->base
.direction
= ___DIRECTION_RD
;
4738 d
->base
.close_direction
= 0; /* prevent closing on errors */
4739 d
->base
.read_stage
= ___STAGE_OPEN
;
4740 d
->base
.write_stage
= ___STAGE_CLOSED
;
4744 d
->ignore_hidden
= ignore_hidden
;
4746 d
->dir
= opendir (path
);
4750 ___SCMOBJ e
= fnf_or_err_code_from_errno ();
4757 #ifdef USE_FindFirstFile
4760 ___CHAR_TYPE(___DIR_OPEN_PATH_CE_SELECT
) dir
[___PATH_MAX_LENGTH
+2+1];
4763 while (path
[i
] != '\0' && i
< ___PATH_MAX_LENGTH
)
4769 if (i
== 0 || (dir
[i
-1] != '\\' && dir
[i
-1] != '/'))
4775 d
->ignore_hidden
= ignore_hidden
;
4778 d
->h
= FindFirstFile (dir
, &d
->fdata
);
4780 if (d
->h
== INVALID_HANDLE_VALUE
)
4782 ___SCMOBJ e
= fnf_or_err_code_from_GetLastError ();
4790 device_transfer_close_responsibility (___CAST(___device
*,d
));
4794 ___device_add_to_group (dgroup
, &d
->base
);
4796 return ___FIX(___NO_ERR
);
4799 ___SCMOBJ ___device_directory_read
4800 ___P((___device_directory
*dev
,
4801 ___STRING_TYPE(___DIR_OPEN_PATH_CE_SELECT
) *name
),
4804 ___device_directory
*dev
;
4805 ___STRING_TYPE(___DIR_OPEN_PATH_CE_SELECT
) *name
;)
4809 if (dev
->base
.read_stage
!= ___STAGE_OPEN
)
4810 return ___FIX(___CLOSED_DEVICE_ERR
);
4814 ___STRING_TYPE(___DIR_OPEN_PATH_CE_SELECT
) temp
;
4818 struct dirent
*de
= readdir (dev
->dir
);
4823 /* this seems to be broken, at least under Linux */
4825 return err_code_from_errno ();
4828 e
= ___FIX(___NO_ERR
);
4834 switch (dev
->ignore_hidden
)
4842 if (temp
[0] == '.' &&
4844 (temp
[1] == '.' && (temp
[2] == '\0'))))
4849 return ___FIX(___NO_ERR
);
4854 #ifdef USE_FindFirstFile
4856 if (dev
->first_file
)
4857 dev
->first_file
= 0;
4858 else if (!FindNextFile (dev
->h
, &dev
->fdata
))
4860 e
= err_code_from_GetLastError ();
4862 if (e
== ___FIX(___WIN32_ERR(ERROR_NO_MORE_FILES
)))
4863 e
= ___FIX(___NO_ERR
);
4867 temp
= dev
->fdata
.cFileName
;
4869 if (temp
[0] == '\0')
4870 temp
= dev
->fdata
.cAlternateFileName
; /* use 8.3 name */
4872 switch (dev
->ignore_hidden
)
4876 if (dev
->fdata
.dwFileAttributes
& FILE_ATTRIBUTE_HIDDEN
)
4880 if (temp
[0] == '.' &&
4882 (temp
[1] == '.' && (temp
[2] == '\0'))))
4887 return ___FIX(___NO_ERR
);
4899 /*---------------------------------------------------------------------------*/
4901 /* Event-queue device. */
4903 typedef struct ___device_event_queue_struct
4914 } ___device_event_queue
;
4916 typedef struct ___device_event_queue_vtbl_struct
4918 ___device_vtbl base
;
4919 } ___device_event_queue_vtbl
;
4921 ___HIDDEN
int ___device_event_queue_kind
4922 ___P((___device
*self
),
4926 return ___EVENT_QUEUE_KIND
;
4929 ___HIDDEN ___SCMOBJ ___device_event_queue_close_virt
4930 ___P((___device
*self
,
4937 ___device_event_queue
*d
= ___CAST(___device_event_queue
*,self
);
4939 if (d
->base
.read_stage
== ___STAGE_CLOSED
)
4940 return ___FIX(___NO_ERR
);
4942 if (direction
& ___DIRECTION_RD
)
4944 d
->base
.read_stage
= ___STAGE_CLOSED
; /* avoid multiple closes */
4947 return ___FIX(___NO_ERR
);
4950 ___HIDDEN ___SCMOBJ ___device_event_queue_select_virt
4951 ___P((___device
*self
,
4952 ___BOOL for_writing
,
4955 ___device_select_state
*state
),
4962 ___BOOL for_writing
;
4965 ___device_select_state
*state
;)
4967 ___device_event_queue
*d
= ___CAST(___device_event_queue
*,self
);
4968 int stage
= (for_writing
4969 ? d
->base
.write_stage
4970 : d
->base
.read_stage
);
4972 if (pass
== ___SELECT_PASS_1
)
4974 if (stage
!= ___STAGE_OPEN
)
4975 state
->timeout
= ___time_mod
.time_neg_infinity
;
4980 state
->message_queue_mask
= d
->event_mask
;
4981 state
->message_queue_dev_pos
= i
;
4986 return ___FIX(___SELECT_SETUP_DONE
);
4989 /* pass == ___SELECT_PASS_CHECK */
4991 if (stage
!= ___STAGE_OPEN
)
4992 state
->devs
[i
] = NULL
;
4997 if (state
->devs_next
[i
] != -1)
4998 state
->devs
[i
] = NULL
;
5003 return ___FIX(___NO_ERR
);
5006 ___HIDDEN ___SCMOBJ ___device_event_queue_release_virt
5007 ___P((___device
*self
),
5011 return ___FIX(___NO_ERR
);
5014 ___HIDDEN ___SCMOBJ ___device_event_queue_force_output_virt
5015 ___P((___device
*self
,
5022 return ___FIX(___NO_ERR
);
5025 ___HIDDEN ___device_event_queue_vtbl ___device_event_queue_table
=
5028 ___device_event_queue_kind
,
5029 ___device_event_queue_select_virt
,
5030 ___device_event_queue_release_virt
,
5031 ___device_event_queue_force_output_virt
,
5032 ___device_event_queue_close_virt
5037 ___SCMOBJ ___device_event_queue_setup
5038 ___P((___device_event_queue
**dev
,
5039 ___device_group
*dgroup
,
5040 ___SCMOBJ selector
),
5044 ___device_event_queue
**dev
;
5045 ___device_group
*dgroup
;
5046 ___SCMOBJ selector
;)
5048 ___device_event_queue
*d
;
5050 d
= ___CAST(___device_event_queue
*,
5051 ___alloc_mem (sizeof (___device_event_queue
)));
5054 return ___FIX(___HEAP_OVERFLOW_ERR
);
5056 d
->base
.vtbl
= &___device_event_queue_table
;
5057 d
->base
.refcount
= 1;
5058 d
->base
.direction
= ___DIRECTION_RD
;
5059 d
->base
.close_direction
= 0; /* prevent closing on errors */
5060 d
->base
.read_stage
= ___STAGE_OPEN
;
5061 d
->base
.write_stage
= ___STAGE_CLOSED
;
5065 d
->event_mask
= ___INT(selector
);
5071 ___device_add_to_group (dgroup
, &d
->base
);
5073 return ___FIX(___NO_ERR
);
5077 ___HIDDEN ___SCMOBJ ___release_event
5083 return ___FIX(___NO_ERR
);
5087 ___SCMOBJ ___device_event_queue_read
5088 ___P((___device_event_queue
*dev
,
5092 ___device_event_queue
*dev
;
5095 if (dev
->base
.read_stage
!= ___STAGE_OPEN
)
5096 return ___FIX(___CLOSED_DEVICE_ERR
);
5101 MSG
*msg
= ___CAST(MSG
*, ___alloc_rc (sizeof (MSG
)));
5104 return ___FIX(___STOC_HEAP_OVERFLOW_ERR
+___RETURN_POS
);
5106 if (GetQueueStatus (dev
->event_mask
) != 0 &&
5108 NULL
, /* retrieve messages for window and thread */
5109 0, /* no constraint on the message type */
5111 PM_REMOVE
)) /* remove message */
5112 return ___NONNULLPOINTER_to_SCMOBJ
5113 (___CAST(void*,msg
),
5119 ___release_rc (msg
);
5124 return ___ERR_CODE_EAGAIN
;
5128 /*---------------------------------------------------------------------------*/
5130 /* File stream device */
5132 typedef struct ___device_file_struct
5134 ___device_stream base
;
5154 typedef struct ___device_file_vtbl_struct
5156 ___device_stream_vtbl base
;
5157 } ___device_file_vtbl
;
5159 ___HIDDEN
int ___device_file_kind
5160 ___P((___device
*self
),
5164 return ___FILE_DEVICE_KIND
;
5169 ___HIDDEN
void ___device_file_restore_initial_mode
5170 ___P((___device_file
*d
),
5176 /* set blocking mode */
5178 set_fd_blocking_mode (d
->fd
, 1); /* ignore error */
5185 ___HIDDEN ___SCMOBJ ___device_file_close_raw_virt
5186 ___P((___device_stream
*self
,
5190 ___device_stream
*self
;
5193 ___device_file
*d
= ___CAST(___device_file
*,self
);
5194 int is_not_closed
= 0;
5196 if (d
->base
.base
.read_stage
!= ___STAGE_CLOSED
)
5197 is_not_closed
|= ___DIRECTION_RD
;
5199 if (d
->base
.base
.write_stage
!= ___STAGE_CLOSED
)
5200 is_not_closed
|= ___DIRECTION_WR
;
5202 if (is_not_closed
== 0)
5203 return ___FIX(___NO_ERR
);
5205 if ((is_not_closed
& ~direction
) == 0)
5207 /* Close file when both sides are closed. */
5209 d
->base
.base
.read_stage
= ___STAGE_CLOSED
; /* avoid multiple closes */
5210 d
->base
.base
.write_stage
= ___STAGE_CLOSED
;
5212 if ((d
->base
.base
.close_direction
& d
->base
.base
.direction
)
5213 == d
->base
.base
.direction
)
5216 ___device_file_restore_initial_mode (d
);
5223 if (___fclose (d
->stream
) != 0)
5224 return err_code_from_errno ();
5230 if (close_no_EINTR (d
->fd
) < 0)
5231 return err_code_from_errno ();
5235 if (!CloseHandle (d
->h
))
5236 return err_code_from_GetLastError ();
5240 else if (is_not_closed
& direction
& ___DIRECTION_RD
)
5241 d
->base
.base
.read_stage
= ___STAGE_CLOSED
;
5242 else if (is_not_closed
& direction
& ___DIRECTION_WR
)
5243 d
->base
.base
.write_stage
= ___STAGE_CLOSED
;
5245 return ___FIX(___NO_ERR
);
5248 ___HIDDEN ___SCMOBJ ___device_file_select_raw_virt
5249 ___P((___device_stream
*self
,
5250 ___BOOL for_writing
,
5253 ___device_select_state
*state
),
5259 ___device_stream
*self
;
5260 ___BOOL for_writing
;
5263 ___device_select_state
*state
;)
5265 ___device_file
*d
= ___CAST(___device_file
*,self
);
5266 int stage
= (for_writing
5267 ? d
->base
.base
.write_stage
5268 : d
->base
.base
.read_stage
);
5270 if (pass
== ___SELECT_PASS_1
)
5272 if (stage
!= ___STAGE_OPEN
)
5273 state
->timeout
= ___time_mod
.time_neg_infinity
;
5279 state
->timeout
= ___time_mod
.time_neg_infinity
;
5285 ___device_select_add_fd (state
, d
->fd
, for_writing
);
5288 return ___FIX(___SELECT_SETUP_DONE
);
5291 /* pass == ___SELECT_PASS_CHECK */
5293 if (stage
!= ___STAGE_OPEN
)
5294 state
->devs
[i
] = NULL
;
5300 state
->devs
[i
] = NULL
;
5308 ? FD_ISSET(d
->fd
, &state
->writefds
)
5309 : FD_ISSET(d
->fd
, &state
->readfds
))
5310 state
->devs
[i
] = NULL
;
5316 if (state
->devs_next
[i
] != -1)
5317 state
->devs
[i
] = NULL
;
5322 return ___FIX(___NO_ERR
);
5325 ___HIDDEN ___SCMOBJ ___device_file_release_raw_virt
5326 ___P((___device_stream
*self
),
5328 ___device_stream
*self
;)
5332 ___device_file
*d
= ___CAST(___device_file
*,self
);
5334 if (d
->base
.base
.read_stage
!= ___STAGE_CLOSED
||
5335 d
->base
.base
.write_stage
!= ___STAGE_CLOSED
)
5336 ___device_file_restore_initial_mode (d
);
5340 return ___FIX(___NO_ERR
);
5343 ___HIDDEN ___SCMOBJ ___device_file_force_output_raw_virt
5344 ___P((___device_stream
*self
,
5348 ___device_stream
*self
;
5351 ___device_file
*d
= ___CAST(___device_file
*,self
);
5353 if (d
->base
.base
.write_stage
== ___STAGE_OPEN
)
5360 ___FILE
*stream
= d
->stream
;
5365 ___fflush (stream
); /* ignore error */
5380 if (fcntl (d
->fd
, F_FULLFSYNC
, 0) < 0)
5381 return err_code_from_errno ();
5388 if (fsync (d
->fd
) < 0)
5389 return err_code_from_errno ();
5397 return ___FIX(___NO_ERR
);
5400 ___HIDDEN ___SCMOBJ ___device_file_seek_raw_virt
5401 ___P((___device_stream
*self
,
5402 ___stream_index
*pos
,
5407 ___device_stream
*self
;
5408 ___stream_index
*pos
;
5411 ___device_file
*d
= ___CAST(___device_file
*,self
);
5413 if (d
->base
.base
.read_stage
== ___STAGE_OPEN
||
5414 d
->base
.base
.write_stage
== ___STAGE_OPEN
)
5420 ___FILE
*stream
= d
->stream
;
5425 if (fseek (stream
, *pos
, whence
) < 0 ||
5426 (new_pos
= ftell (stream
)) < 0)
5427 return err_code_from_errno ();
5438 if ((new_pos
= lseek (d
->fd
, *pos
, whence
)) < 0)
5439 return err_code_from_errno ();
5447 LARGE_INTEGER new_pos
;
5449 new_pos
.QuadPart
= *pos
;
5451 new_pos
.LowPart
= SetFilePointer (d
->h
,
5456 if (new_pos
.LowPart
== 0xFFFFFFFF
5457 && GetLastError () != NO_ERROR
)
5458 return err_code_from_GetLastError ();
5460 *pos
= new_pos
.LowPart
; /************* incomplete... support large offsets */
5465 return ___FIX(___NO_ERR
);
5468 ___HIDDEN ___SCMOBJ ___device_file_read_raw_virt
5469 ___P((___device_stream
*self
,
5471 ___stream_index len
,
5472 ___stream_index
*len_done
),
5477 ___device_stream
*self
;
5479 ___stream_index len
;
5480 ___stream_index
*len_done
;)
5482 ___device_file
*d
= ___CAST(___device_file
*,self
);
5484 if (d
->base
.base
.read_stage
!= ___STAGE_OPEN
)
5485 return ___FIX(___CLOSED_DEVICE_ERR
);
5492 ___FILE
*stream
= d
->stream
;
5497 if (stream
== ___stdin
)
5498 len
= 1; /* only read 1 byte at a time to prevent blocking on tty */
5500 if ((n
= fread (buf
, 1, len
, stream
)) == 0)
5502 if (ferror (stream
))
5505 return ___FIX(___UNKNOWN_ERR
);
5521 if ((n
= read (d
->fd
, buf
, len
)) < 0)
5522 return err_code_from_errno ();
5534 if (!ReadFile (d
->h
, buf
, len
, &n
, NULL
))
5535 return err_code_from_GetLastError ();
5542 return ___FIX(___NO_ERR
);
5545 ___HIDDEN ___SCMOBJ ___device_file_write_raw_virt
5546 ___P((___device_stream
*self
,
5548 ___stream_index len
,
5549 ___stream_index
*len_done
),
5554 ___device_stream
*self
;
5556 ___stream_index len
;
5557 ___stream_index
*len_done
;)
5559 ___device_file
*d
= ___CAST(___device_file
*,self
);
5561 if (d
->base
.base
.write_stage
!= ___STAGE_OPEN
)
5562 return ___FIX(___CLOSED_DEVICE_ERR
);
5569 ___FILE
*stream
= d
->stream
;
5574 if ((n
= fwrite (buf
, 1, len
, stream
)) == 0)
5576 if (ferror (stream
))
5579 return ___FIX(___UNKNOWN_ERR
);
5594 if ((n
= write (d
->fd
, buf
, len
)) < 0)
5595 return err_code_from_errno ();
5607 if (d
->flags
& (1 << 3))
5609 ___stream_index pos
= 0; /* end of file */
5610 ___SCMOBJ e
= ___device_file_seek_raw_virt (self
, &pos
, FILE_END
);
5611 if (e
!= ___FIX(___NO_ERR
))
5615 if (!WriteFile (d
->h
, buf
, len
, &n
, NULL
))
5616 return err_code_from_GetLastError ();
5623 return ___FIX(___NO_ERR
);
5627 ___HIDDEN ___SCMOBJ ___device_file_width_virt
5628 ___P((___device_stream
*self
),
5630 ___device_stream
*self
;)
5636 ___HIDDEN ___SCMOBJ ___device_file_default_options_virt
5637 ___P((___device_stream
*self
),
5639 ___device_stream
*self
;)
5641 int settings
= ___setup_params
.file_settings
;
5642 int char_encoding_errors
= ___CHAR_ENCODING_ERRORS(settings
);
5643 int char_encoding
= ___CHAR_ENCODING(settings
);
5644 int eol_encoding
= ___EOL_ENCODING(settings
);
5645 int buffering
= ___BUFFERING(settings
);
5647 if (char_encoding_errors
== 0)
5648 char_encoding_errors
= ___CHAR_ENCODING_ERRORS_ON
;
5650 if (char_encoding
== 0)
5651 char_encoding
= ___CHAR_ENCODING_ISO_8859_1
;
5653 if (eol_encoding
== 0)
5654 eol_encoding
= ___EOL_ENCODING_LF
;
5660 ___device_file
*d
= ___CAST(___device_file
*,self
);
5662 if (GetFileType (d
->h
) == FILE_TYPE_PIPE
)
5663 buffering
= ___NO_BUFFERING
;
5665 buffering
= ___FULL_BUFFERING
;
5671 buffering
= ___FULL_BUFFERING
;
5677 ___printf ("file char_encoding_errors=%d char_encoding=%d eol_encoding=%d buffering=%d\n",
5678 char_encoding_errors
,
5685 return ___FIX(___STREAM_OPTIONS(char_encoding_errors
,
5689 char_encoding_errors
,
5696 ___HIDDEN ___SCMOBJ ___device_file_options_set_virt
5697 ___P((___device_stream
*self
,
5701 ___device_stream
*self
;
5704 return ___FIX(___NO_ERR
);
5708 ___HIDDEN ___device_file_vtbl ___device_file_table
=
5712 ___device_file_kind
,
5713 ___device_stream_select_virt
,
5714 ___device_stream_release_virt
,
5715 ___device_stream_force_output_virt
,
5716 ___device_stream_close_virt
5718 ___device_file_select_raw_virt
,
5719 ___device_file_release_raw_virt
,
5720 ___device_file_force_output_raw_virt
,
5721 ___device_file_close_raw_virt
,
5722 ___device_file_seek_raw_virt
,
5723 ___device_file_read_raw_virt
,
5724 ___device_file_write_raw_virt
,
5725 ___device_file_width_virt
,
5726 ___device_file_default_options_virt
,
5727 ___device_file_options_set_virt
5735 ___HIDDEN ___SCMOBJ ___device_file_setup_from_stream
5736 ___P((___device_file
**dev
,
5737 ___device_group
*dgroup
,
5744 ___device_file
**dev
;
5745 ___device_group
*dgroup
;
5751 d
= ___CAST(___device_file
*,
5752 ___alloc_mem (sizeof (___device_file
)));
5755 return ___FIX(___HEAP_OVERFLOW_ERR
);
5757 d
->base
.base
.vtbl
= &___device_file_table
;
5762 return ___device_stream_setup
5775 ___HIDDEN ___SCMOBJ ___device_file_setup_from_fd
5776 ___P((___device_file
**dev
,
5777 ___device_group
*dgroup
,
5784 ___device_file
**dev
;
5785 ___device_group
*dgroup
;
5791 d
= ___CAST(___device_file
*,
5792 ___alloc_mem (sizeof (___device_file
)));
5795 return ___FIX(___HEAP_OVERFLOW_ERR
);
5797 d
->base
.base
.vtbl
= &___device_file_table
;
5802 return ___device_stream_setup
5814 ___HIDDEN ___SCMOBJ ___device_file_setup_from_handle
5815 ___P((___device_file
**dev
,
5816 ___device_group
*dgroup
,
5827 ___device_file
**dev
;
5828 ___device_group
*dgroup
;
5836 d
= ___CAST(___device_file
*,
5837 ___alloc_mem (sizeof (___device_file
)));
5840 return ___FIX(___HEAP_OVERFLOW_ERR
);
5842 d
->base
.base
.vtbl
= &___device_file_table
;
5848 return ___device_stream_setup
5858 /*---------------------------------------------------------------------------*/
5863 ___SCMOBJ ___device_stream_setup_from_stream
5864 ___P((___device_stream
**dev
,
5865 ___device_group
*dgroup
,
5874 ___device_stream
**dev
;
5875 ___device_group
*dgroup
;
5883 if ((e
= ___device_file_setup_from_stream
5888 == ___FIX(___NO_ERR
))
5889 *dev
= ___CAST(___device_stream
*,d
);
5895 ___HIDDEN
void device_translate_flags
5906 switch ((flags
>> 4) & 3)
5911 *direction
= ___DIRECTION_RD
;
5915 *direction
= ___DIRECTION_WR
;
5919 *direction
= ___DIRECTION_RD
|___DIRECTION_WR
;
5930 ___HIDDEN
int ___device_stream_kind_from_fd
5936 * Determine what kind of device is attached to the file descriptor
5937 * (tty, socket, or regular file).
5941 return ___TTY_DEVICE_KIND
;
5948 if (___fstat (fd
, &s
) < 0)
5949 return ___NONE_KIND
;
5951 if (S_ISREG(s
.st_mode
))
5952 return ___FILE_DEVICE_KIND
;
5956 if (S_ISDIR(s
.st_mode
))
5959 if (S_ISLNK(s
.st_mode
))
5964 if (S_ISCHR(s
.st_mode
))
5965 return ___FILE_DEVICE_KIND
;
5967 if (S_ISBLK(s
.st_mode
))
5968 return ___FILE_DEVICE_KIND
;
5970 if (S_ISFIFO(s
.st_mode
))
5971 return ___FILE_DEVICE_KIND
;
5973 #ifdef USE_NETWORKING
5974 if (S_ISSOCK(s
.st_mode
))
5975 return ___TCP_CLIENT_DEVICE_KIND
;
5979 return ___NONE_KIND
;
5983 return ___FILE_DEVICE_KIND
;
5989 ___HIDDEN
int ___device_stream_direction_from_fd
5994 int direction
= ___DIRECTION_RD
|___DIRECTION_WR
;
5998 * A "read" and "write" of 0 bytes is attempted to tell which
5999 * directions the file descriptor supports.
6002 if (read (fd
, buf
, 0) < 0)
6003 direction
&= ~___DIRECTION_RD
;
6005 if (write (fd
, buf
, 0) < 0)
6006 direction
&= ~___DIRECTION_WR
;
6009 * It is likely that on some systems a zero length "read" and
6010 * "write" will return an error, regardless of the possible
6011 * operations. In this case assume that both operations are
6016 direction
= ___DIRECTION_RD
|___DIRECTION_WR
;
6022 ___SCMOBJ ___device_stream_setup_from_fd
6023 ___P((___device_stream
**dev
,
6024 ___device_group
*dgroup
,
6033 ___device_stream
**dev
;
6034 ___device_group
*dgroup
;
6039 ___SCMOBJ e
= ___FIX(___UNKNOWN_ERR
);
6041 if (kind
== ___NONE_KIND
)
6042 kind
= ___device_stream_kind_from_fd (fd
);
6045 direction
= ___device_stream_direction_from_fd (fd
);
6048 ___printf ("fd=%d kind=%d direction=%d\n", fd
, kind
, direction
);
6051 if (kind
== ___TTY_DEVICE_KIND
)
6054 * No need to setup the file descriptor to perform nonblocking
6055 * I/O because that is done by os_tty.c in a way that restores
6056 * the blocking mode to its original mode when the process
6057 * exits. Restoring the original mode avoids some issues when
6058 * running under a shell in emacs (which gives a "Process
6059 * shell finished" error when the program terminates).
6064 if ((e
= ___device_tty_setup_from_fd
6069 == ___FIX(___NO_ERR
))
6070 *dev
= ___CAST(___device_stream
*,d
);
6077 #ifdef USE_NETWORKING
6079 case ___TCP_CLIENT_DEVICE_KIND
:
6081 ___device_tcp_client
*d
;
6082 struct sockaddr server_addr
;
6084 if ((e
= ___device_tcp_client_setup_from_socket
6092 == ___FIX(___NO_ERR
))
6093 *dev
= ___CAST(___device_stream
*,d
);
6100 case ___FILE_DEVICE_KIND
:
6104 #ifdef USE_NONBLOCKING_FILE_IO
6107 * Setup file descriptor to perform nonblocking I/O.
6110 if (set_fd_blocking_mode (fd
, 0) != 0) /* set nonblocking mode */
6111 return err_code_from_errno ();
6115 if ((e
= ___device_file_setup_from_fd
6120 == ___FIX(___NO_ERR
))
6121 *dev
= ___CAST(___device_stream
*,d
);
6128 e
= ___FIX(___UNKNOWN_ERR
);
6138 ___HIDDEN
void device_translate_flags
6151 switch ((flags
>> 4) & 3)
6156 *direction
= ___DIRECTION_RD
;
6160 *direction
= ___DIRECTION_WR
;
6164 *direction
= ___DIRECTION_RD
|___DIRECTION_WR
;
6168 if (flags
& (1 << 3))
6171 switch ((flags
>> 1) & 3)
6175 case 1: f
|= O_CREAT
; break;
6176 case 2: f
|= O_CREAT
|O_EXCL
; break;
6183 * The O_NONBLOCK flag is not needed here because the file
6184 * descriptor will be set to nonblocking mode later on. But we do
6185 * it anyway so there is no moment in time when it is in blocking
6199 ___HIDDEN
int ___device_stream_kind_from_handle
6205 CONSOLE_CURSOR_INFO cinfo
;
6207 BY_HANDLE_FILE_INFORMATION finfo
;
6210 ___printf ("GetFileType -> %d\n", ___CAST(int,GetFileType (h
)));
6213 if (GetNumberOfConsoleInputEvents (h
, &n
))
6214 return ___TTY_DEVICE_KIND
;
6216 if (GetConsoleCursorInfo (h
, &cinfo
))
6217 return ___TTY_DEVICE_KIND
;
6219 if (GetCommState (h
, &dcb
))
6220 return ___SERIAL_DEVICE_KIND
;
6222 if (GetFileType (h
) == FILE_TYPE_PIPE
)
6223 return ___PIPE_DEVICE_KIND
;
6225 if (GetFileInformationByHandle (h
, &finfo
))
6226 return ___FILE_DEVICE_KIND
;
6228 return ___NONE_KIND
;
6232 ___HIDDEN
int ___device_stream_direction_from_handle
6238 int direction
= ___DIRECTION_RD
|___DIRECTION_WR
;
6241 * A "ReadFile" and "WriteFile" of 0 bytes is attempted to tell which
6242 * directions the file handle supports.
6245 if (!ReadFile (h
, NULL
, 0, &n
, NULL
))
6246 direction
&= ~___DIRECTION_RD
;
6248 if (!WriteFile (h
, NULL
, 0, &n
, NULL
))
6249 direction
&= ~___DIRECTION_WR
;
6252 * It is likely that on some systems a zero length "ReadFile" and
6253 * "WriteFile" will return an error, regardless of the possible
6254 * operations. In this case assume that both operations are
6259 direction
= ___DIRECTION_RD
|___DIRECTION_WR
;
6265 ___SCMOBJ ___device_stream_setup_from_handle
6266 ___P((___device_stream
**dev
,
6267 ___device_group
*dgroup
,
6278 ___device_stream
**dev
;
6279 ___device_group
*dgroup
;
6285 ___SCMOBJ e
= ___FIX(___UNKNOWN_ERR
);
6287 if (kind
== ___NONE_KIND
)
6288 kind
= ___device_stream_kind_from_handle (h
);
6291 direction
= ___device_stream_direction_from_handle (h
);
6294 ___printf ("kind=%d direction=%d\n", kind
, direction
);
6299 case ___TTY_DEVICE_KIND
:
6302 if ((e
= ___device_tty_setup_from_console
6306 == ___FIX(___NO_ERR
))
6307 *dev
= ___CAST(___device_stream
*,d
);
6311 case ___SERIAL_DEVICE_KIND
:
6313 ___device_serial
*d
;
6314 if ((e
= ___device_serial_setup_from_handle
6319 == ___FIX(___NO_ERR
))
6320 *dev
= ___CAST(___device_stream
*,d
);
6324 case ___FILE_DEVICE_KIND
:
6327 if ((e
= ___device_file_setup_from_handle
6334 == ___FIX(___NO_ERR
))
6335 *dev
= ___CAST(___device_stream
*,d
);
6339 case ___PIPE_DEVICE_KIND
:
6342 if ((e
= ___device_pipe_setup_from_handle
6349 == ___FIX(___NO_ERR
))
6350 *dev
= ___CAST(___device_stream
*,d
);
6356 e
= ___FIX(___UNKNOWN_ERR
);
6361 if (e
== ___FIX(___NO_ERR
))
6362 device_transfer_close_responsibility (___CAST(___device
*,*dev
));
6368 ___HIDDEN
void device_translate_flags
6372 DWORD
*creation_mode
,
6384 DWORD
*creation_mode
;
6391 switch ((flags
>> 4) & 3)
6396 *direction
= ___DIRECTION_RD
;
6400 *direction
= ___DIRECTION_WR
;
6403 am
= GENERIC_READ
|GENERIC_WRITE
;
6404 *direction
= ___DIRECTION_RD
|___DIRECTION_WR
;
6408 switch ((flags
>> 1) & 3)
6413 cm
= TRUNCATE_EXISTING
;
6431 *share_mode
= FILE_SHARE_READ
|FILE_SHARE_WRITE
|FILE_SHARE_DELETE
;
6432 *creation_mode
= cm
;
6433 *attributes
= FILE_ATTRIBUTE_NORMAL
;
6439 /*---------------------------------------------------------------------------*/
6442 #define ___STREAM_OPEN_PROCESS_CE_SELECT(latin1,utf8,ucs2,ucs4,wchar,native) native
6445 #undef ___STREAM_OPEN_PROCESS_CE_SELECT
6450 #ifdef USE_CreateProcess
6452 #define ___STREAM_OPEN_PROCESS_CE_SELECT(latin1,utf8,ucs2,ucs4,wchar,native) ucs2
6453 #define CP_ENV_FLAGS CREATE_UNICODE_ENVIRONMENT
6455 #define ___STREAM_OPEN_PROCESS_CE_SELECT(latin1,utf8,ucs2,ucs4,wchar,native) native
6456 #define CP_ENV_FLAGS 0
6461 #ifdef ___STREAM_OPEN_PROCESS_CE_SELECT
6465 /**********************************/
6468 typedef struct half_duplex_pipe
6474 typedef struct full_duplex_pipe
6476 half_duplex_pipe input
;
6477 half_duplex_pipe output
;
6481 ___HIDDEN
int open_half_duplex_pipe
6482 ___P((half_duplex_pipe
*hdp
),
6484 half_duplex_pipe
*hdp
;)
6493 #ifdef USE_socketpair
6494 if (socketpair (AF_UNIX
, SOCK_STREAM
, 0, fds
) < 0)
6498 hdp
->reading_fd
= fds
[0];
6499 hdp
->writing_fd
= fds
[1];
6504 ___HIDDEN
void close_half_duplex_pipe
6505 ___P((half_duplex_pipe
*hdp
,
6509 half_duplex_pipe
*hdp
;
6512 if (end
!= 1 && hdp
->reading_fd
>= 0)
6514 close_no_EINTR (hdp
->reading_fd
); /* ignore error */
6515 hdp
->reading_fd
= -1;
6518 if (end
!= 0 && hdp
->writing_fd
>= 0)
6520 close_no_EINTR (hdp
->writing_fd
); /* ignore error */
6521 hdp
->writing_fd
= -1;
6525 ___HIDDEN
int open_pseudo_terminal_master
6526 ___P((int *master_fd_ptr
,
6535 return openpty (master_fd_ptr
, slave_fd_ptr
, NULL
, NULL
, NULL
);
6541 return *master_fd_ptr
= getpt ();
6546 return *master_fd_ptr
= open ("/dev/ptmx", O_RDWR
| O_NOCTTY
);
6555 /***************************/
6559 #include <stropts.h>
6560 extern char *ptsname (int __fd
);
6564 ___HIDDEN
int setup_terminal_slave
6565 ___P((int slave_fd
),
6569 struct termios tios
;
6571 if (tcgetattr (slave_fd
, &tios
) >= 0)
6573 tios
.c_lflag
&= ~(ECHO
| ECHOCTL
| ICANON
| IEXTEN
| ISIG
);
6574 tios
.c_iflag
&= ~(BRKINT
| INLCR
| ICRNL
| INPCK
| ISTRIP
| IXON
| IXOFF
);
6575 tios
.c_cflag
&= ~(CSIZE
| PARENB
| CLOCAL
);
6576 tios
.c_cflag
|= (CS8
| HUPCL
);
6580 tios
.c_oflag
&= ~(OPOST
| ONLCR
| OCRNL
);
6582 if (tcsetattr (slave_fd
, TCSANOW
, &tios
) >= 0)
6590 ___HIDDEN
int open_pseudo_terminal_slave
6591 ___P((int master_fd
,
6601 errno
= xxx
;/********************/
6618 if (grantpt (master_fd
) >= 0 &&
6619 unlockpt (master_fd
) >= 0 &&
6620 (name
= ptsname (master_fd
)) != NULL
&&
6621 (fd
= open (name
, O_RDWR
)) >= 0)
6626 #ifndef HAVE_isastream
6631 || (ioctl (fd
, I_PUSH
, "ptem") >= 0 &&
6632 ioctl (fd
, I_PUSH
, "ldterm") >= 0)
6642 close_no_EINTR (fd
); /* ignore error */
6652 ___HIDDEN
int open_full_duplex_pipe1
6653 ___P((full_duplex_pipe
*fdp
,
6657 full_duplex_pipe
*fdp
;
6660 fdp
->input
.reading_fd
= -1;
6661 fdp
->input
.writing_fd
= -1;
6662 fdp
->output
.reading_fd
= -1;
6663 fdp
->output
.writing_fd
= -1;
6669 if (open_pseudo_terminal_master (&master_fd
, &slave_fd
) >= 0)
6673 if ((master_fd_dup
= dup_no_EINTR (master_fd
)) >= 0)
6675 fdp
->input
.writing_fd
= master_fd
;
6676 fdp
->output
.reading_fd
= master_fd_dup
;
6677 fdp
->input
.reading_fd
= slave_fd
;
6681 close_no_EINTR (master_fd
); /* ignore error */
6683 close_no_EINTR (slave_fd
); /* ignore error */
6689 if (open_half_duplex_pipe (&fdp
->input
) >= 0)
6691 if (open_half_duplex_pipe (&fdp
->output
) >= 0)
6693 close_half_duplex_pipe (&fdp
->input
, 2);
6701 ___HIDDEN
int open_full_duplex_pipe2
6702 ___P((full_duplex_pipe
*fdp
,
6706 full_duplex_pipe
*fdp
;
6711 if (setsid () >= 0 &&
6713 ioctl (fdp
->input
.reading_fd
, TIOCSCTTY
, 0) >= 0 &&
6715 open_pseudo_terminal_slave (fdp
->input
.writing_fd
,
6716 &fdp
->input
.reading_fd
) >= 0)
6719 if (setup_terminal_slave (fdp
->input
.reading_fd
) >= 0 &&
6720 (fdp
->output
.writing_fd
= dup_no_EINTR (fdp
->input
.reading_fd
)) >= 0)
6723 close_no_EINTR (fdp
->input
.reading_fd
); /* ignore error */
6736 #ifdef USE_CreateProcess
6738 #define ___ESCAPE_PROCESS_ARGS
6740 ___STRING_TYPE(___STREAM_OPEN_PROCESS_CE_SELECT
) argv_to_ccmd
6741 ___P((___STRING_TYPE(___STREAM_OPEN_PROCESS_CE_SELECT
) *argv
),
6743 ___STRING_TYPE(___STREAM_OPEN_PROCESS_CE_SELECT
) *argv
;)
6745 ___STRING_TYPE(___STREAM_OPEN_PROCESS_CE_SELECT
) ccmd
;
6748 ___STRING_TYPE(___STREAM_OPEN_PROCESS_CE_SELECT
) arg
;
6750 while ((arg
= argv
[i
]) != NULL
)
6754 while (arg
[j
] != ___UNICODE_NUL
)
6759 #ifdef ___ESCAPE_PROCESS_ARGS
6762 ___BOOL double_backslash
= TRUE
;
6766 ___CHAR_TYPE(___STREAM_OPEN_PROCESS_CE_SELECT
) c
= arg
[j
];
6767 if (c
== ___UNICODE_DOUBLEQUOTE
||
6768 (double_backslash
&& c
== ___UNICODE_BACKSLASH
))
6770 double_backslash
= TRUE
;
6774 double_backslash
= FALSE
;
6785 ccmd
= ___CAST(___STRING_TYPE(___STREAM_OPEN_PROCESS_CE_SELECT
),
6786 ___alloc_mem (ccmd_len
* sizeof (*ccmd
)));
6790 ccmd
[--ccmd_len
] = ___UNICODE_NUL
;
6798 while (arg
[j
] != ___UNICODE_NUL
)
6801 #ifdef ___ESCAPE_PROCESS_ARGS
6804 ___BOOL double_backslash
= TRUE
;
6806 ccmd
[--ccmd_len
] = ___UNICODE_DOUBLEQUOTE
;
6810 ___CHAR_TYPE(___STREAM_OPEN_PROCESS_CE_SELECT
) c
= arg
[j
];
6811 ccmd
[--ccmd_len
] = c
;
6812 if (c
== ___UNICODE_DOUBLEQUOTE
||
6813 (double_backslash
&& c
== ___UNICODE_BACKSLASH
))
6815 ccmd
[--ccmd_len
] = ___UNICODE_BACKSLASH
;
6816 double_backslash
= TRUE
;
6819 double_backslash
= FALSE
;
6822 ccmd
[--ccmd_len
] = ___UNICODE_DOUBLEQUOTE
;
6829 ___CHAR_TYPE(___STREAM_OPEN_PROCESS_CE_SELECT
) c
= arg
[j
];
6830 ccmd
[--ccmd_len
] = c
;
6836 ccmd
[--ccmd_len
] = ___UNICODE_SPACE
;
6843 ___STRING_TYPE(___STREAM_OPEN_PROCESS_CE_SELECT
) env_to_cenv
6844 ___P((___STRING_TYPE(___STREAM_OPEN_PROCESS_CE_SELECT
) *env
),
6846 ___STRING_TYPE(___STREAM_OPEN_PROCESS_CE_SELECT
) *env
;)
6848 ___STRING_TYPE(___STREAM_OPEN_PROCESS_CE_SELECT
) cenv
;
6851 ___STRING_TYPE(___STREAM_OPEN_PROCESS_CE_SELECT
) varval
;
6853 while ((varval
= env
[i
++]) != NULL
)
6856 while (varval
[j
++] != ___UNICODE_NUL
)
6863 cenv
= ___CAST(___STRING_TYPE(___STREAM_OPEN_PROCESS_CE_SELECT
),
6864 ___alloc_mem (cenv_len
* sizeof (*cenv
)));
6868 ___STRING_TYPE(___STREAM_OPEN_PROCESS_CE_SELECT
) p
= cenv
;
6871 while ((varval
= env
[i
++]) != NULL
)
6874 while ((*p
++ = varval
[j
++]) != ___UNICODE_NUL
)
6878 *p
++ = ___UNICODE_NUL
;
6887 ___SCMOBJ ___device_stream_setup_from_process
6888 ___P((___device_stream
**dev
,
6889 ___device_group
*dgroup
,
6890 ___STRING_TYPE(___STREAM_OPEN_PROCESS_CE_SELECT
) *argv
,
6891 ___STRING_TYPE(___STREAM_OPEN_PROCESS_CE_SELECT
) *env
,
6892 ___STRING_TYPE(___STREAM_OPEN_PROCESS_CE_SELECT
) dir
,
6900 ___device_stream
**dev
;
6901 ___device_group
*dgroup
;
6902 ___STRING_TYPE(___STREAM_OPEN_PROCESS_CE_SELECT
) *argv
;
6903 ___STRING_TYPE(___STREAM_OPEN_PROCESS_CE_SELECT
) *env
;
6904 ___STRING_TYPE(___STREAM_OPEN_PROCESS_CE_SELECT
) dir
;
6907 #define STDIN_REDIR 1
6908 #define STDOUT_REDIR 2
6909 #define STDERR_REDIR 4
6910 #define PSEUDO_TERM 8
6911 #define SHOW_CONSOLE 16
6915 ___SCMOBJ e
= ___FIX(___NO_ERR
);
6917 ___device_process
*d
;
6919 half_duplex_pipe hdp_errno
;
6920 full_duplex_pipe fdp
;
6925 * Block SIGCHLD so that if the process is created the
6926 * sigchld_signal_handler will find it in the device group.
6929 sigset_type oldmask
= block_signal (SIGCHLD
);
6931 fdp
.input
.writing_fd
= -1;
6932 fdp
.output
.reading_fd
= -1;
6934 if (open_half_duplex_pipe (&hdp_errno
) < 0)
6935 e
= err_code_from_errno ();
6938 if ((options
& (STDIN_REDIR
| STDOUT_REDIR
| STDERR_REDIR
)) &&
6939 open_full_duplex_pipe1 (&fdp
, options
& PSEUDO_TERM
) < 0)
6940 e
= err_code_from_errno ();
6943 ___disable_os_interrupts ();
6945 if ((pid
= fork ()) < 0)
6947 e
= err_code_from_errno ();
6948 if (options
& (STDIN_REDIR
| STDOUT_REDIR
| STDERR_REDIR
))
6950 close_half_duplex_pipe (&fdp
.input
, 2);
6951 close_half_duplex_pipe (&fdp
.output
, 2);
6956 ___enable_os_interrupts ();
6959 if (e
!= ___FIX(___NO_ERR
))
6960 close_half_duplex_pipe (&hdp_errno
, 2);
6963 if (e
== ___FIX(___NO_ERR
))
6969 restore_sigmask (oldmask
);
6971 ___cleanup_os_interrupt_handling ();
6973 if (options
& (STDIN_REDIR
| STDOUT_REDIR
| STDERR_REDIR
))
6975 if (open_full_duplex_pipe2 (&fdp
, options
& PSEUDO_TERM
) < 0 ||
6976 ((options
& STDIN_REDIR
) &&
6977 dup2_no_EINTR (fdp
.input
.reading_fd
, STDIN_FILENO
) < 0) ||
6978 ((options
& STDOUT_REDIR
) &&
6979 dup2_no_EINTR (fdp
.output
.writing_fd
, STDOUT_FILENO
) < 0) ||
6980 ((options
& (STDERR_REDIR
| PSEUDO_TERM
)) &&
6981 dup2_no_EINTR (fdp
.output
.writing_fd
, STDERR_FILENO
) < 0))
6985 if (fcntl (hdp_errno
.writing_fd
, F_SETFD
, FD_CLOEXEC
) < 0)
6988 close_half_duplex_pipe (&fdp
.input
, 1);
6989 close_half_duplex_pipe (&fdp
.output
, 0);
6990 close_half_duplex_pipe (&hdp_errno
, 0);
6993 /* Close all file descriptors that aren't used. */
6995 int fd
= sysconf (_SC_OPEN_MAX
) - 1;
6999 if (fd
!= STDIN_FILENO
&&
7000 fd
!= STDOUT_FILENO
&&
7001 fd
!= STDERR_FILENO
&&
7002 fd
!= hdp_errno
.writing_fd
)
7003 close_no_EINTR (fd
); /* ignore error */
7008 if (dir
== NULL
|| chdir (dir
) == 0)
7014 execvp (argv
[0], argv
);
7015 /* the exec failed, errno will be returned to parent */
7020 /* return the errno to the parent process */
7022 execvp_errno
= errno
;
7024 write (hdp_errno
.writing_fd
, &execvp_errno
, sizeof (execvp_errno
));
7026 close_half_duplex_pipe (&fdp
.input
, 0);
7027 close_half_duplex_pipe (&fdp
.output
, 1);
7028 close_half_duplex_pipe (&hdp_errno
, 1);
7033 /* parent process */
7035 if (options
& (STDIN_REDIR
| STDOUT_REDIR
| STDERR_REDIR
))
7037 close_half_duplex_pipe (&fdp
.input
, 0);
7038 close_half_duplex_pipe (&fdp
.output
, 1);
7041 close_half_duplex_pipe (&hdp_errno
, 1);
7044 * The following call to read has been known to fail with EINTR,
7045 * in particular on OpenBSD 4.5. This is probably because the
7046 * child process that is started terminates before the parent
7047 * process doing the read has time to wakeup. So the parent
7048 * process receives a SIGCHLD signal which interrupts the read.
7051 n
= read_no_EINTR (hdp_errno
.reading_fd
,
7053 sizeof (execvp_errno
));
7056 e
= err_code_from_errno ();
7057 else if (n
== sizeof (execvp_errno
))
7059 errno
= execvp_errno
;
7060 e
= err_code_from_errno ();
7063 e
= ___FIX(___UNKNOWN_ERR
);
7066 direction
= ___DIRECTION_RD
|___DIRECTION_WR
;
7068 e
= ___device_process_setup_from_pid
7072 fdp
.input
.writing_fd
,
7073 fdp
.output
.reading_fd
,
7076 *dev
= ___CAST(___device_stream
*,d
);
7078 if (e
== ___FIX(___NO_ERR
))
7079 device_transfer_close_responsibility (___CAST(___device
*,d
));
7082 if (e
!= ___FIX(___NO_ERR
))
7083 if (options
& (STDIN_REDIR
| STDOUT_REDIR
| STDERR_REDIR
))
7085 close_half_duplex_pipe (&fdp
.input
, 1);
7086 close_half_duplex_pipe (&fdp
.output
, 0);
7089 close_half_duplex_pipe (&hdp_errno
, 0);
7092 restore_sigmask (oldmask
);
7098 #ifdef USE_CreateProcess
7102 ___device_process
*d
;
7104 ___STRING_TYPE(___STREAM_OPEN_PROCESS_CE_SELECT
) ccmd
;
7105 ___STRING_TYPE(___STREAM_OPEN_PROCESS_CE_SELECT
) cenv
= NULL
;
7107 HANDLE hstdin_rd
= NULL
;
7108 HANDLE hstdin_wr
= NULL
;
7109 HANDLE hstdout_rd
= NULL
;
7110 HANDLE hstdout_wr
= NULL
;
7112 SECURITY_ATTRIBUTES sa
;
7113 PROCESS_INFORMATION pi
;
7116 sa
.nLength
= sizeof (SECURITY_ATTRIBUTES
);
7117 sa
.bInheritHandle
= TRUE
;
7118 sa
.lpSecurityDescriptor
= NULL
;
7120 if ((ccmd
= argv_to_ccmd (argv
)) == NULL
||
7121 (env
!= NULL
&& (cenv
= env_to_cenv (env
)) == NULL
))
7122 e
= ___FIX(___HEAP_OVERFLOW_ERR
);
7125 ZeroMemory (&pi
, sizeof (pi
));
7127 ZeroMemory (&si
, sizeof (si
));
7128 si
.cb
= sizeof (si
);
7130 si
.hStdInput
= GetStdHandle (STD_INPUT_HANDLE
);
7131 si
.hStdOutput
= GetStdHandle (STD_OUTPUT_HANDLE
);
7132 si
.hStdError
= GetStdHandle (STD_ERROR_HANDLE
);
7134 if (options
& STDIN_REDIR
)
7136 if (!CreatePipe (&hstdin_rd
, &hstdin_wr
, &sa
, 0))
7137 e
= err_code_from_GetLastError ();
7140 SetHandleInformation (hstdin_wr
, HANDLE_FLAG_INHERIT
, 0);
7141 si
.hStdInput
= hstdin_rd
;
7145 if (options
& (STDOUT_REDIR
| STDERR_REDIR
))
7147 if (!CreatePipe (&hstdout_rd
, &hstdout_wr
, &sa
, 0))
7148 e
= err_code_from_GetLastError ();
7151 SetHandleInformation (hstdout_rd
, HANDLE_FLAG_INHERIT
, 0);
7152 if (options
& STDOUT_REDIR
)
7153 si
.hStdOutput
= hstdout_wr
;
7154 if (options
& STDERR_REDIR
)
7155 si
.hStdError
= hstdout_wr
;
7159 si
.dwFlags
|= STARTF_USESTDHANDLES
;
7162 if (hstdin_wr
!= NULL
)
7165 if (DuplicateHandle (GetCurrentProcess (),
7167 GetCurrentProcess (),
7171 DUPLICATE_SAME_ACCESS
))
7173 CloseHandle (hstdin_wr
);
7178 if (hstdout_rd
!= NULL
)
7181 if (DuplicateHandle (GetCurrentProcess (),
7183 GetCurrentProcess (),
7187 DUPLICATE_SAME_ACCESS
))
7189 CloseHandle (hstdout_rd
);
7195 if (si
.hStdError
== INVALID_HANDLE_VALUE
||
7197 (NULL
, /* module name */
7198 ccmd
, /* command line */
7199 NULL
, /* process handle not inheritable */
7200 NULL
, /* thread handle not inheritable */
7201 TRUE
, /* set handle inheritance to TRUE */
7202 (CP_ENV_FLAGS
| ((options
& SHOW_CONSOLE
) ? 0 : CREATE_NO_WINDOW
)), /* creation flags */
7203 cenv
, /* child's environment */
7204 dir
, /* child's starting directory */
7205 &si
, /* pointer to STARTUPINFO structure */
7206 &pi
)) /* pointer to PROCESS_INFORMATION structure */
7207 e
= err_code_from_GetLastError ();
7210 direction
= ___DIRECTION_RD
|___DIRECTION_WR
;
7212 e
= ___device_process_setup_from_process
7220 *dev
= ___CAST(___device_stream
*,d
);
7222 if (e
== ___FIX(___NO_ERR
))
7223 device_transfer_close_responsibility (___CAST(___device
*,d
));
7227 if (hstdout_rd
!= NULL
)
7228 CloseHandle (hstdout_wr
); /* ignore error */
7230 if (hstdin_rd
!= NULL
)
7231 CloseHandle (hstdin_rd
); /* ignore error */
7233 if (e
!= ___FIX(___NO_ERR
))
7235 if (hstdout_rd
!= NULL
)
7236 CloseHandle (hstdout_rd
); /* ignore error */
7238 if (hstdin_rd
!= NULL
)
7239 CloseHandle (hstdin_wr
); /* ignore error */
7256 ___SCMOBJ ___os_device_process_pid
7257 ___P((___SCMOBJ dev
),
7261 ___device_process
*d
=
7262 ___CAST(___device_process
*,___FIELD(dev
,___FOREIGN_PTR
));
7274 return ___FIX(d
->pid
);
7280 return ___FIX(d
->pi
.dwProcessId
);
7286 ___SCMOBJ ___os_device_process_status
7287 ___P((___SCMOBJ dev
),
7291 ___device_process
*d
=
7292 ___CAST(___device_process
*,___FIELD(dev
,___FOREIGN_PTR
));
7295 if ((e
= ___device_process_status_poll (d
)) != ___FIX(___NO_ERR
))
7301 return ___FIX(d
->status
);
7305 /*---------------------------------------------------------------------------*/
7309 #define ___STREAM_OPEN_PATH_CE_SELECT(latin1,utf8,ucs2,ucs4,wchar,native) native
7314 #define ___STREAM_OPEN_PATH_CE_SELECT(latin1,utf8,ucs2,ucs4,wchar,native) native
7319 #define ___STREAM_OPEN_PATH_CE_SELECT(latin1,utf8,ucs2,ucs4,wchar,native) ucs2
7321 #define ___STREAM_OPEN_PATH_CE_SELECT(latin1,utf8,ucs2,ucs4,wchar,native) native
7326 #ifdef ___STREAM_OPEN_PATH_CE_SELECT
7328 ___SCMOBJ ___device_stream_setup_from_path
7329 ___P((___device_stream
**dev
,
7330 ___device_group
*dgroup
,
7331 ___STRING_TYPE(___STREAM_OPEN_PATH_CE_SELECT
) path
,
7339 ___device_stream
**dev
;
7340 ___device_group
*dgroup
;
7341 ___STRING_TYPE(___STREAM_OPEN_PATH_CE_SELECT
) path
;
7354 device_translate_flags (flags
,
7359 ___printf ("path=\"%s\" mode=%s\n", path
, mod
);
7362 if ((stream
= ___fopen (path
, mod
)) == 0)
7363 return fnf_or_err_code_from_errno ();
7365 if ((e
= ___device_stream_setup_from_stream
7371 != ___FIX(___NO_ERR
))
7372 ___fclose (stream
); /* ignore error */
7383 device_translate_flags (flags
,
7388 ___printf ("path=\"%s\" fl=%d\n", path
, fl
);
7391 if ((fd
= open (path
,
7398 return fnf_or_err_code_from_errno ();
7400 if ((e
= ___device_stream_setup_from_fd
7406 != ___FIX(___NO_ERR
))
7407 close_no_EINTR (fd
); /* ignore error */
7415 DWORD creation_mode
;
7420 device_translate_flags (flags
,
7427 h
= CreateFile (path
,
7435 if (h
== INVALID_HANDLE_VALUE
)
7436 return fnf_or_err_code_from_GetLastError ();
7438 if ((e
= ___device_stream_setup_from_handle
7445 != ___FIX(___NO_ERR
))
7446 CloseHandle (h
); /* ignore error */
7450 if (e
== ___FIX(___NO_ERR
))
7451 device_transfer_close_responsibility (___CAST(___device
*,*dev
));
7459 /*---------------------------------------------------------------------------*/
7461 /* Device operations. */
7463 ___SCMOBJ ___os_device_kind
7464 ___P((___SCMOBJ dev
),
7468 ___device
*d
= ___CAST(___device
*,___FIELD(dev
,___FOREIGN_PTR
));
7470 return ___FIX(___device_kind (d
));
7474 ___SCMOBJ ___os_device_force_output
7475 ___P((___SCMOBJ dev
,
7482 ___device
*d
= ___CAST(___device
*,___FIELD(dev
,___FOREIGN_PTR
));
7484 return ___device_force_output (d
, ___INT(level
));
7488 ___SCMOBJ ___os_device_close
7489 ___P((___SCMOBJ dev
,
7490 ___SCMOBJ direction
),
7494 ___SCMOBJ direction
;)
7496 ___device
*d
= ___CAST(___device
*,___FIELD(dev
,___FOREIGN_PTR
));
7498 return ___device_close (d
, ___INT(direction
));
7502 /* - - - - - - - - - - - - - - - - - - */
7504 /* Stream device operations. */
7506 ___SCMOBJ ___os_device_stream_seek
7507 ___P((___SCMOBJ dev
,
7517 ___device_stream
*d
=
7518 ___CAST(___device_stream
*,___FIELD(dev
,___FOREIGN_PTR
));
7523 if ((e
= ___SCMOBJ_to_S32 (pos
, &p
, 2)) == ___FIX(___NO_ERR
))
7524 e
= ___device_stream_seek (d
, &p
, ___INT(whence
));
7526 if (e
!= ___FIX(___NO_ERR
) ||
7527 (e
= ___S32_to_SCMOBJ (p
, &result
, ___RETURN_POS
)) != ___FIX(___NO_ERR
))
7534 ___SCMOBJ ___os_device_stream_read
7535 ___P((___SCMOBJ dev
,
7548 ___device_stream
*d
=
7549 ___CAST(___device_stream
*,___FIELD(dev
,___FOREIGN_PTR
));
7550 ___stream_index len_done
;
7553 if ((e
= ___device_stream_read
7555 ___CAST(___U8
*,___BODY_AS(buffer
,___tSUBTYPED
)) + ___INT(lo
),
7556 ___INT(hi
) - ___INT(lo
),
7558 == ___FIX(___NO_ERR
))
7559 return ___FIX(len_done
);
7565 ___SCMOBJ ___os_device_stream_write
7566 ___P((___SCMOBJ dev
,
7579 ___device_stream
*d
=
7580 ___CAST(___device_stream
*,___FIELD(dev
,___FOREIGN_PTR
));
7581 ___stream_index len_done
;
7584 if ((e
= ___device_stream_write
7586 ___CAST(___U8
*,___BODY_AS(buffer
,___tSUBTYPED
)) + ___INT(lo
),
7587 ___INT(hi
) - ___INT(lo
),
7589 == ___FIX(___NO_ERR
))
7590 return ___FIX(len_done
);
7596 ___SCMOBJ ___os_device_stream_width
7597 ___P((___SCMOBJ dev
),
7601 ___device_stream
*d
=
7602 ___CAST(___device_stream
*,___FIELD(dev
,___FOREIGN_PTR
));
7604 return ___device_stream_width (d
);
7608 ___SCMOBJ ___os_device_stream_default_options
7609 ___P((___SCMOBJ dev
),
7613 ___device_stream
*d
=
7614 ___CAST(___device_stream
*,___FIELD(dev
,___FOREIGN_PTR
));
7616 return ___device_stream_default_options (d
);
7620 ___SCMOBJ ___os_device_stream_options_set
7621 ___P((___SCMOBJ dev
,
7628 ___device_stream
*d
=
7629 ___CAST(___device_stream
*,___FIELD(dev
,___FOREIGN_PTR
));
7631 return ___device_stream_options_set (d
, options
);
7635 /* - - - - - - - - - - - - - - - - - - */
7637 /* Opening a predefined device (stdin, stdout, stderr, console, etc). */
7639 ___SCMOBJ ___os_device_stream_open_predefined
7640 ___P((___SCMOBJ index
,
7648 * The parameter "index" identifies the stream which is to be
7649 * associated with the returned device. The stream must be
7650 * currently open. The responsibility for closing the stream is not
7651 * transferred to the runtime system because the client may have to
7652 * do I/O on the stream after the runtime system terminates (for
7653 * example output on stdout).
7657 ___device_stream
*dev
;
7667 device_translate_flags (___INT(flags
),
7671 switch (___INT(index
))
7675 switch (___INT(index
))
7690 stream
= fdopen (___INT(index
), mode
);
7694 if ((e
= ___device_stream_setup_from_stream
7696 ___global_device_group (),
7700 != ___FIX(___NO_ERR
))
7716 device_translate_flags (___INT(flags
),
7720 switch (___INT(index
))
7726 if ((e
= ___device_tty_setup_console
7728 ___global_device_group (),
7730 != ___FIX(___NO_ERR
))
7733 dev
= ___CAST(___device_stream
*,d
);
7740 switch (___INT(index
))
7756 if ((e
= ___device_stream_setup_from_fd
7758 ___global_device_group (),
7762 != ___FIX(___NO_ERR
))
7775 DWORD creation_mode
;
7780 device_translate_flags (___INT(flags
),
7787 switch (___INT(index
))
7794 if ((e
= ___device_tty_setup_console
7796 ___global_device_group (),
7798 != ___FIX(___NO_ERR
))
7801 dev
= ___CAST(___device_stream
*,d
);
7808 switch (___INT(index
))
7812 h
= GetStdHandle (STD_INPUT_HANDLE
);
7815 h
= GetStdHandle (STD_OUTPUT_HANDLE
);
7818 h
= GetStdHandle (STD_ERROR_HANDLE
);
7822 if (h
== INVALID_HANDLE_VALUE
)
7823 return err_code_from_GetLastError ();
7825 if (GetFileType (h
) == FILE_TYPE_UNKNOWN
)
7828 if ((e
= ___device_stream_setup_from_handle
7830 ___global_device_group (),
7835 != ___FIX(___NO_ERR
))
7844 e
= ___NONNULLPOINTER_to_SCMOBJ
7847 ___device_cleanup_from_ptr
,
7851 if (e
!= ___FIX(___NO_ERR
))
7853 ___device_cleanup (___CAST(___device
*,dev
)); /* ignore error */
7857 ___release_scmobj (result
);
7863 /* - - - - - - - - - - - - - - - - - - */
7865 /* Opening a path. */
7867 ___SCMOBJ ___os_device_stream_open_path
7868 ___P((___SCMOBJ path
,
7878 #ifndef ___STREAM_OPEN_PATH_CE_SELECT
7880 return ___FIX(___UNIMPL_ERR
);
7886 ___device_stream
*dev
;
7889 if ((e
= ___SCMOBJ_to_NONNULLSTRING
7893 ___CE(___STREAM_OPEN_PATH_CE_SELECT
),
7895 != ___FIX(___NO_ERR
))
7899 ___STRING_TYPE(___STREAM_OPEN_PATH_CE_SELECT
) p
=
7900 ___CAST(___STRING_TYPE(___STREAM_OPEN_PATH_CE_SELECT
),cpath
);
7902 if ((e
= ___device_stream_setup_from_path
7904 ___global_device_group (),
7908 != ___FIX(___NO_ERR
))
7912 if ((e
= ___NONNULLPOINTER_to_SCMOBJ
7915 ___device_cleanup_from_ptr
,
7918 != ___FIX(___NO_ERR
))
7920 ___device_cleanup (___CAST(___device
*,dev
)); /* ignore error */
7925 ___release_string (cpath
);
7928 ___release_scmobj (result
);
7936 /* - - - - - - - - - - - - - - - - - - */
7938 /* Opening a process. */
7940 ___SCMOBJ ___os_device_stream_open_process
7941 ___P((___SCMOBJ path_and_args
,
7942 ___SCMOBJ environment
,
7943 ___SCMOBJ directory
,
7949 ___SCMOBJ path_and_args
;
7950 ___SCMOBJ environment
;
7951 ___SCMOBJ directory
;
7954 #ifndef ___STREAM_OPEN_PROCESS_CE_SELECT
7956 return ___FIX(___UNIMPL_ERR
);
7961 ___device_stream
*dev
;
7967 if ((e
= ___SCMOBJ_to_NONNULLSTRINGLIST
7971 ___CE(___STREAM_OPEN_PROCESS_CE_SELECT
)))
7972 != ___FIX(___NO_ERR
) ||
7973 (environment
!= ___FAL
&&
7974 (e
= ___SCMOBJ_to_NONNULLSTRINGLIST
7978 ___CE(___STREAM_OPEN_PROCESS_CE_SELECT
)))
7979 != ___FIX(___NO_ERR
)) ||
7980 (directory
!= ___FAL
&&
7981 (e
= ___SCMOBJ_to_NONNULLSTRING
7985 ___CE(___STREAM_OPEN_PROCESS_CE_SELECT
),
7987 != ___FIX(___NO_ERR
)) ||
7988 (e
= ___device_stream_setup_from_process
7990 ___global_device_group (),
7991 ___CAST(___STRING_TYPE(___STREAM_OPEN_PROCESS_CE_SELECT
)*,argv
),
7992 ___CAST(___STRING_TYPE(___STREAM_OPEN_PROCESS_CE_SELECT
)*,env
),
7993 ___CAST(___STRING_TYPE(___STREAM_OPEN_PROCESS_CE_SELECT
),dir
),
7995 != ___FIX(___NO_ERR
))
7999 if ((e
= ___NONNULLPOINTER_to_SCMOBJ
8002 ___device_cleanup_from_ptr
,
8005 == ___FIX(___NO_ERR
))
8006 ___release_scmobj (result
);
8010 ___release_string_list (argv
);
8013 ___release_string_list (env
);
8016 ___release_string (dir
);
8026 ___HIDDEN
void sigchld_signal_handler
8032 ___set_signal_handler (SIGCHLD
, sigchld_signal_handler
);
8036 * A SIGCHLD signal indicates that at least one child has changed
8037 * status. There may be more than one because signals are not
8038 * queued. For example during a period when the SIGCHLD signal is
8039 * blocked several child processes can terminate and only one call
8040 * to the SIGCHLD handler will occur when the SIGCHLD signal is
8041 * unblocked. For this reason we must call waitpid in a loop, until
8042 * the last call indicates that no other child process is available.
8049 pid_t pid
= waitpid_no_EINTR (-1, &status
, WNOHANG
);
8055 * Find the process device structure for the process which
8056 * terminated, and save the exit status with the process device.
8059 head
= ___global_device_group ()->list
;
8063 ___device
*d
= head
->prev
;
8067 if (___device_kind (d
) == ___PROCESS_DEVICE_KIND
)
8069 ___device_process
*dev
= ___CAST(___device_process
*,d
);
8071 if (dev
->pid
== pid
)
8073 if (WIFEXITED(status
) || WIFSIGNALED(status
))
8074 ___device_process_status_set (dev
, status
); /* ignore error */
8079 } while (d
!= head
);
8087 /* - - - - - - - - - - - - - - - - - - */
8089 /* Opening a TCP client. */
8091 ___SCMOBJ ___os_device_tcp_client_open
8092 ___P((___SCMOBJ server_addr
,
8098 ___SCMOBJ server_addr
;
8102 #ifndef USE_NETWORKING
8104 return ___FIX(___UNIMPL_ERR
);
8109 ___device_tcp_client
*dev
;
8114 if ((e
= ___SCMOBJ_to_sockaddr (server_addr
, port_num
, &sa
, &salen
, 1))
8115 != ___FIX(___NO_ERR
))
8118 if ((e
= ___device_tcp_client_setup_from_sockaddr
8120 ___global_device_group (),
8124 ___DIRECTION_RD
|___DIRECTION_WR
))
8125 != ___FIX(___NO_ERR
))
8128 if ((e
= ___NONNULLPOINTER_to_SCMOBJ
8131 ___device_cleanup_from_ptr
,
8134 != ___FIX(___NO_ERR
))
8136 ___device_cleanup (___CAST(___device
*,dev
)); /* ignore error */
8140 ___release_scmobj (result
);
8148 ___SCMOBJ ___os_device_tcp_client_socket_info
8149 ___P((___SCMOBJ dev
,
8156 #ifndef USE_NETWORKING
8158 return ___FIX(___UNIMPL_ERR
);
8162 ___device_tcp_client
*d
=
8163 ___CAST(___device_tcp_client
*,___FIELD(dev
,___FOREIGN_PTR
));
8165 SOCKET_LEN_TYPE salen
;
8167 if (d
->try_connect_again
!= 0)
8169 if (try_connect (d
) == 0)
8171 if (d
->try_connect_again
!= 0)
8172 return ___ERR_CODE_EAGAIN
;
8175 return ERR_CODE_FROM_SOCKET_CALL
;
8178 salen
= sizeof (sa
);
8180 if (((peer
== ___FAL
)
8181 ? getsockname (d
->s
, &sa
, &salen
)
8182 : getpeername (d
->s
, &sa
, &salen
)) < 0)
8184 ___SCMOBJ e
= ERR_CODE_FROM_SOCKET_CALL
;
8185 if (NOT_CONNECTED(e
) && !d
->connect_done
)
8186 e
= ___ERR_CODE_EAGAIN
;
8190 return ___sockaddr_to_SCMOBJ (&sa
, salen
, ___RETURN_POS
);
8196 /* - - - - - - - - - - - - - - - - - - */
8198 /* Opening and reading a TCP server. */
8200 ___SCMOBJ ___os_device_tcp_server_open
8201 ___P((___SCMOBJ server_addr
,
8209 ___SCMOBJ server_addr
;
8214 #ifndef USE_NETWORKING
8216 return ___FIX(___UNIMPL_ERR
);
8221 ___device_tcp_server
*dev
;
8226 if ((e
= ___SCMOBJ_to_sockaddr (server_addr
, port_num
, &sa
, &salen
, 1))
8227 != ___FIX(___NO_ERR
))
8230 e
= ___device_tcp_server_setup
8232 ___global_device_group (),
8238 if (e
!= ___FIX(___NO_ERR
))
8241 e
= ___NONNULLPOINTER_to_SCMOBJ
8244 ___device_cleanup_from_ptr
,
8248 if (e
!= ___FIX(___NO_ERR
))
8250 ___device_cleanup (___CAST(___device
*,dev
)); /* ignore error */
8254 ___release_scmobj (result
);
8262 ___SCMOBJ ___os_device_tcp_server_read
8263 ___P((___SCMOBJ dev
),
8267 #ifndef USE_NETWORKING
8269 return ___FIX(___UNIMPL_ERR
);
8273 ___device_tcp_server
*d
=
8274 ___CAST(___device_tcp_server
*,___FIELD(dev
,___FOREIGN_PTR
));
8276 ___device_tcp_client
*client
;
8279 if ((e
= ___device_tcp_server_read (d
, ___global_device_group (), &client
))
8280 != ___FIX(___NO_ERR
))
8283 e
= ___NONNULLPOINTER_to_SCMOBJ
8286 ___device_cleanup_from_ptr
,
8290 if (e
!= ___FIX(___NO_ERR
))
8292 ___device_cleanup (___CAST(___device
*,d
)); /* ignore error */
8296 ___release_scmobj (result
);
8304 ___SCMOBJ ___os_device_tcp_server_socket_info
8305 ___P((___SCMOBJ dev
),
8309 #ifndef USE_NETWORKING
8311 return ___FIX(___UNIMPL_ERR
);
8315 ___device_tcp_server
*d
=
8316 ___CAST(___device_tcp_server
*,___FIELD(dev
,___FOREIGN_PTR
));
8318 SOCKET_LEN_TYPE salen
;
8320 salen
= sizeof (sa
);
8322 if (getsockname (d
->s
, &sa
, &salen
) < 0)
8323 return ERR_CODE_FROM_SOCKET_CALL
;
8325 return ___sockaddr_to_SCMOBJ (&sa
, salen
, ___RETURN_POS
);
8331 /* - - - - - - - - - - - - - - - - - - */
8333 /* Opening and reading a directory. */
8335 ___SCMOBJ ___os_device_directory_open_path
8336 ___P((___SCMOBJ path
,
8337 ___SCMOBJ ignore_hidden
),
8341 ___SCMOBJ ignore_hidden
;)
8343 #ifndef ___DIR_OPEN_PATH_CE_SELECT
8345 return ___FIX(___UNIMPL_ERR
);
8351 ___device_directory
*dev
;
8354 if ((e
= ___SCMOBJ_to_NONNULLSTRING
8358 ___CE(___DIR_OPEN_PATH_CE_SELECT
),
8360 != ___FIX(___NO_ERR
))
8364 ___STRING_TYPE(___DIR_OPEN_PATH_CE_SELECT
) p
=
8365 ___CAST(___STRING_TYPE(___DIR_OPEN_PATH_CE_SELECT
),cpath
);
8367 if ((e
= ___device_directory_setup
8369 ___global_device_group (),
8371 ___INT(ignore_hidden
)))
8372 != ___FIX(___NO_ERR
))
8376 if ((e
= ___NONNULLPOINTER_to_SCMOBJ
8379 ___device_cleanup_from_ptr
,
8382 != ___FIX(___NO_ERR
))
8384 ___device_cleanup (___CAST(___device
*,dev
)); /* ignore error */
8389 ___release_string (cpath
);
8392 ___release_scmobj (result
);
8400 ___SCMOBJ ___os_device_directory_read
8401 ___P((___SCMOBJ dev
),
8405 #ifndef ___DIR_OPEN_PATH_CE_SELECT
8407 return ___FIX(___UNIMPL_ERR
);
8411 ___device_directory
*d
=
8412 ___CAST(___device_directory
*,___FIELD(dev
,___FOREIGN_PTR
));
8414 ___STRING_TYPE(___DIR_OPEN_PATH_CE_SELECT
) name
;
8417 if ((e
= ___device_directory_read (d
, &name
)) != ___FIX(___NO_ERR
))
8423 if ((e
= ___STRING_to_SCMOBJ (name
, &result
, ___RETURN_POS
, ___CE(___DIR_OPEN_PATH_CE_SELECT
) ))
8424 != ___FIX(___NO_ERR
))
8427 ___release_scmobj (result
);
8435 /* - - - - - - - - - - - - - - - - - - */
8437 /* Opening an event-queue. */
8439 ___SCMOBJ ___os_device_event_queue_open
8440 ___P((___SCMOBJ selector
),
8442 ___SCMOBJ selector
;)
8446 ___device_event_queue
*dev
;
8448 if ((e
= ___device_event_queue_setup
8450 ___global_device_group (),
8452 != ___FIX(___NO_ERR
))
8456 if ((e
= ___NONNULLPOINTER_to_SCMOBJ
8459 ___device_cleanup_from_ptr
,
8462 != ___FIX(___NO_ERR
))
8464 ___device_cleanup (___CAST(___device
*,dev
)); /* ignore error */
8469 ___release_scmobj (result
);
8475 ___SCMOBJ ___os_device_event_queue_read
8476 ___P((___SCMOBJ dev
),
8480 ___device_event_queue
*d
=
8481 ___CAST(___device_event_queue
*,___FIELD(dev
,___FOREIGN_PTR
));
8485 if ((e
= ___device_event_queue_read (d
, &result
)) != ___FIX(___NO_ERR
))
8488 ___release_scmobj (result
);
8494 /* - - - - - - - - - - - - - - - - - - */
8496 /* Waiting for I/O to become possible on a set of devices. */
8498 ___SCMOBJ ___os_condvar_select
8499 ___P((___SCMOBJ run_queue
,
8503 ___SCMOBJ run_queue
;
8506 /******************/
8507 #define ___BTQ_DEQ_NEXT 1
8508 #define ___BTQ_DEQ_PREV 2
8509 #define ___BTQ_COLOR 3
8510 #define ___BTQ_PARENT 4
8511 #define ___BTQ_LEFT 5
8512 #define ___BTQ_RIGHT 6
8513 #define ___BTQ_LEFTMOST 6
8514 #define ___BTQ_OWNER 7
8515 #define ___CONDVAR_NAME 8
8519 ___device
*devs
[MAX_CONDVARS
];
8520 ___SCMOBJ condvars
[MAX_CONDVARS
];
8527 if (timeout
== ___FAL
)
8528 to
= ___time_mod
.time_neg_infinity
;
8529 else if (timeout
== ___TRU
)
8530 to
= ___time_mod
.time_pos_infinity
;
8532 ___time_from_seconds (&to
, ___F64VECTORREF(timeout
,___FIX(0)));
8535 write_pos
= MAX_CONDVARS
;
8536 condvar
= ___FIELD(run_queue
,___BTQ_DEQ_NEXT
);
8538 while (condvar
!= run_queue
)
8540 ___SCMOBJ owner
= ___FIELD(condvar
,___BTQ_OWNER
);
8541 if (read_pos
< write_pos
)
8543 if (owner
& ___FIX(2))
8544 condvars
[--write_pos
] = condvar
;
8546 condvars
[read_pos
++] = condvar
;
8547 ___FIELD(condvar
,___BTQ_OWNER
) = owner
& ~___FIX(1);
8551 to
= ___time_mod
.time_neg_infinity
;
8552 ___FIELD(condvar
,___BTQ_OWNER
) = owner
| ___FIX(1);
8554 condvar
= ___FIELD(condvar
,___BTQ_DEQ_NEXT
);
8559 while (i
< read_pos
)
8561 devs
[i
] = ___CAST(___device
*,
8562 ___FIELD(___FIELD(condvars
[i
],___CONDVAR_NAME
),
8569 while (j
> write_pos
)
8572 devs
[i
] = ___CAST(___device
*,
8573 ___FIELD(___FIELD(condvars
[j
],___CONDVAR_NAME
),
8578 e
= ___device_select (devs
, read_pos
, MAX_CONDVARS
-write_pos
, to
);
8582 while (i
< read_pos
)
8584 if (devs
[i
] == NULL
)
8586 condvar
= condvars
[i
];
8587 ___FIELD(condvar
,___BTQ_OWNER
) |= ___FIX(1);
8594 while (j
> write_pos
)
8597 if (devs
[i
] == NULL
)
8599 condvar
= condvars
[j
];
8600 ___FIELD(condvar
,___BTQ_OWNER
) |= ___FIX(1);
8609 /* - - - - - - - - - - - - - - - - - - */
8612 * Decoding and encoding of a buffer of Scheme characters to a buffer
8617 * The following definitions must match the structure of ports defined
8621 #define ___PORT_MUTEX 1
8622 #define ___PORT_RKIND 2
8623 #define ___PORT_WKIND 3
8624 #define ___PORT_NAME 4
8625 #define ___PORT_READ_DATUM 5
8626 #define ___PORT_WRITE_DATUM 6
8627 #define ___PORT_NEWLINE 7
8628 #define ___PORT_FORCE_OUTPUT 8
8629 #define ___PORT_CLOSE 9
8630 #define ___PORT_ROPTIONS 10
8631 #define ___PORT_RTIMEOUT 11
8632 #define ___PORT_RTIMEOUT_THUNK 12
8633 #define ___PORT_SET_RTIMEOUT 13
8634 #define ___PORT_WOPTIONS 14
8635 #define ___PORT_WTIMEOUT 15
8636 #define ___PORT_WTIMEOUT_THUNK 16
8637 #define ___PORT_SET_WTIMEOUT 17
8639 #define ___PORT_OBJECT_OTHER1 18
8640 #define ___PORT_OBJECT_OTHER2 19
8641 #define ___PORT_OBJECT_OTHER3 20
8643 #define ___PORT_CHAR_RBUF 18
8644 #define ___PORT_CHAR_RLO 19
8645 #define ___PORT_CHAR_RHI 20
8646 #define ___PORT_CHAR_RCHARS 21
8647 #define ___PORT_CHAR_RLINES 22
8648 #define ___PORT_CHAR_RCURLINE 23
8649 #define ___PORT_CHAR_RBUF_FILL 24
8650 #define ___PORT_CHAR_PEEK_EOFP 25
8652 #define ___PORT_CHAR_WBUF 26
8653 #define ___PORT_CHAR_WLO 27
8654 #define ___PORT_CHAR_WHI 28
8655 #define ___PORT_CHAR_WCHARS 29
8656 #define ___PORT_CHAR_WLINES 30
8657 #define ___PORT_CHAR_WCURLINE 31
8658 #define ___PORT_CHAR_WBUF_DRAIN 32
8659 #define ___PORT_INPUT_READTABLE 33
8660 #define ___PORT_OUTPUT_READTABLE 34
8661 #define ___PORT_OUTPUT_WIDTH 35
8663 #define ___PORT_CHAR_OTHER1 36
8664 #define ___PORT_CHAR_OTHER2 37
8665 #define ___PORT_CHAR_OTHER3 38
8666 #define ___PORT_CHAR_OTHER4 39
8667 #define ___PORT_CHAR_OTHER5 40
8669 #define ___PORT_BYTE_RBUF 36
8670 #define ___PORT_BYTE_RLO 37
8671 #define ___PORT_BYTE_RHI 38
8672 #define ___PORT_BYTE_RBUF_FILL 39
8674 #define ___PORT_BYTE_WBUF 40
8675 #define ___PORT_BYTE_WLO 41
8676 #define ___PORT_BYTE_WHI 42
8677 #define ___PORT_BYTE_WBUF_DRAIN 43
8679 #define ___PORT_BYTE_OTHER1 44
8680 #define ___PORT_BYTE_OTHER2 45
8682 #define ___PORT_RDEVICE_CONDVAR 44
8683 #define ___PORT_WDEVICE_CONDVAR 45
8685 #define ___PORT_DEVICE_OTHER1 46
8686 #define ___PORT_DEVICE_OTHER2 47
8688 #define ___C ___CS_SELECT(___U8,___U16,___U32)
8690 ___SCMOBJ ___os_port_decode_chars
8691 ___P((___SCMOBJ port
,
8701 ___SCMOBJ e
= ___FIX(___NO_ERR
);
8702 ___SCMOBJ cbuf
= ___FIELD(port
,___PORT_CHAR_RBUF
);
8703 int chi
= ___INT(___FIELD(port
,___PORT_CHAR_RHI
));
8704 int cend
= ___INT(___STRINGLENGTH(cbuf
));
8705 ___SCMOBJ bbuf
= ___FIELD(port
,___PORT_BYTE_RBUF
);
8706 int blo
= ___INT(___FIELD(port
,___PORT_BYTE_RLO
));
8707 int bhi
= ___INT(___FIELD(port
,___PORT_BYTE_RHI
));
8708 int options
= ___INT(___FIELD(port
,___PORT_ROPTIONS
));
8709 ___C
*cbuf_ptr
= ___CAST(___C
*,___BODY_AS(cbuf
,___tSUBTYPED
));
8710 ___U8
*bbuf_ptr
= ___CAST(___U8
*,___BODY_AS(bbuf
,___tSUBTYPED
));
8717 int w
= ___INT(want
);
8722 cbuf_avail
= cend
- chi
;
8723 bbuf_avail
= bhi
- blo
;
8725 code
= chars_from_bytes (cbuf_ptr
+ chi
,
8732 * either the character buffer is full (cbuf_avail == 0) or no more
8733 * characters can be extracted from the byte buffer either because
8734 * the remaining bytes are not long enough to form a character or
8735 * don't form a valid character.
8738 if (cbuf_avail
== cend
- chi
)
8740 if (code
== ___INCOMPLETE_CHAR
&& eof
!= ___FAL
)
8742 bbuf_avail
= 0; /* skip bytes up to end-of-file */
8743 code
= ___ILLEGAL_CHAR
;
8746 if (code
== ___ILLEGAL_CHAR
)
8748 if (___CHAR_ENCODING_ERRORS(options
) != ___CHAR_ENCODING_ERRORS_OFF
)
8749 e
= err_code_from_char_encoding (___CHAR_ENCODING(options
), 1, 0, 0);
8752 if (___CHAR_ENCODING_SUPPORTS_BMP(___CHAR_ENCODING(options
)))
8753 cbuf_ptr
[chi
] = ___UNICODE_REPLACEMENT
;
8755 cbuf_ptr
[chi
] = ___UNICODE_QUESTION
;
8762 ___FIELD(port
,___PORT_CHAR_RHI
) = ___FIX(cend
- cbuf_avail
);
8763 ___FIELD(port
,___PORT_BYTE_RLO
) = ___FIX(bhi
- bbuf_avail
);
8764 ___FIELD(port
,___PORT_ROPTIONS
) = ___FIX(options
);
8770 ___SCMOBJ ___os_port_encode_chars
8771 ___P((___SCMOBJ port
),
8775 ___SCMOBJ e
= ___FIX(___NO_ERR
);
8776 ___SCMOBJ cbuf
= ___FIELD(port
,___PORT_CHAR_WBUF
);
8777 int clo
= ___INT(___FIELD(port
,___PORT_CHAR_WLO
));
8778 int chi
= ___INT(___FIELD(port
,___PORT_CHAR_WHI
));
8779 ___SCMOBJ bbuf
= ___FIELD(port
,___PORT_BYTE_WBUF
);
8780 int bhi
= ___INT(___FIELD(port
,___PORT_BYTE_WHI
));
8781 int bend
= ___INT(___U8VECTORLENGTH(bbuf
));
8782 int options
= ___INT(___FIELD(port
,___PORT_WOPTIONS
));
8783 ___C
*cbuf_ptr
= ___CAST(___C
*,___BODY_AS(cbuf
,___tSUBTYPED
));
8784 ___U8
*bbuf_ptr
= ___CAST(___U8
*,___BODY_AS(bbuf
,___tSUBTYPED
));
8789 cbuf_avail
= chi
- clo
;
8790 bbuf_avail
= bend
- bhi
;
8792 code
= chars_to_bytes (cbuf_ptr
+ clo
,
8799 * either the character buffer is empty (cbuf_avail == 0) or there
8800 * is not enough space left in the byte buffer for encoding the next
8801 * character, or the next character is illegal for the given
8805 if (cbuf_avail
== chi
- clo
)
8806 if (code
== ___ILLEGAL_CHAR
)
8808 if (___CHAR_ENCODING_ERRORS(options
) != ___CHAR_ENCODING_ERRORS_OFF
)
8810 cbuf_avail
--; /* skip illegal char */
8811 e
= err_code_from_char_encoding (___CHAR_ENCODING(options
), 0, 0, 0);
8815 ___C replacement_cbuf
[1];
8816 int replacement_cbuf_avail
= 1;
8818 if (___CHAR_ENCODING_SUPPORTS_BMP(___CHAR_ENCODING(options
)))
8819 replacement_cbuf
[0] = ___UNICODE_REPLACEMENT
;
8821 replacement_cbuf
[0] = ___UNICODE_QUESTION
;
8823 code
= chars_to_bytes (replacement_cbuf
,
8824 &replacement_cbuf_avail
,
8825 bbuf_ptr
+ bend
- bbuf_avail
,
8830 * skip over the illegal character if the replacement
8831 * character was encoded
8834 cbuf_avail
= cbuf_avail
- 1 + replacement_cbuf_avail
;
8838 ___FIELD(port
,___PORT_CHAR_WLO
) = ___FIX(chi
- cbuf_avail
);
8839 ___FIELD(port
,___PORT_BYTE_WHI
) = ___FIX(bend
- bbuf_avail
);
8840 ___FIELD(port
,___PORT_WOPTIONS
) = ___FIX(options
);
8846 /*---------------------------------------------------------------------------*/
8848 /* I/O module initialization/finalization. */
8851 ___HIDDEN ___SCMOBJ io_module_setup ___PVOID
8855 if ((e
= ___device_group_setup (&___io_mod
.dgroup
)) == ___FIX(___NO_ERR
))
8859 ___set_signal_handler (SIGCHLD
, sigchld_signal_handler
);
8865 #define WINSOCK_MAJOR 1
8866 #define WINSOCK_MINOR 1
8868 WSADATA winsock_data
;
8870 if (!WSAStartup (MAKEWORD(WINSOCK_MAJOR
, WINSOCK_MINOR
), &winsock_data
))
8872 if (LOBYTE(winsock_data
.wVersion
) == WINSOCK_MINOR
&&
8873 HIBYTE(winsock_data
.wVersion
) == WINSOCK_MAJOR
)
8874 return ___FIX(___NO_ERR
);
8875 WSACleanup (); /* ignore error */
8878 e
= ___FIX(___UNKNOWN_ERR
);
8880 ___device_group_cleanup (___io_mod
.dgroup
);
8889 ___HIDDEN
void io_module_cleanup ___PVOID
8893 ___set_signal_handler (SIGCHLD
, SIG_DFL
);
8899 WSACleanup (); /* ignore error */
8903 ___device_group_cleanup (___io_mod
.dgroup
);
8908 ___SCMOBJ ___setup_io_module ___PVOID
8910 if (!___io_mod
.setup
)
8914 ___SCMOBJ e
= ___FIX(___NO_ERR
);
8916 ___io_mod
.always_signaled
= NULL
;
8917 ___io_mod
.abort_select
= NULL
;
8919 ___io_mod
.always_signaled
=
8920 CreateEvent (NULL
, /* can't inherit */
8921 TRUE
, /* manual reset */
8922 TRUE
, /* signaled */
8923 NULL
); /* no name */
8925 if (___io_mod
.always_signaled
== NULL
)
8926 e
= err_code_from_GetLastError ();
8929 ___io_mod
.abort_select
=
8930 CreateEvent (NULL
, /* can't inherit */
8931 TRUE
, /* manual reset */
8932 FALSE
, /* not signaled */
8933 NULL
); /* no name */
8935 if (___io_mod
.abort_select
== NULL
)
8937 CloseHandle (___io_mod
.always_signaled
); /* ignore error */
8938 e
= err_code_from_GetLastError ();
8944 io_module_setup ();/*****************************/
8945 ___io_mod
.setup
= 1;
8946 return ___FIX(___NO_ERR
);
8949 return ___FIX(___UNKNOWN_ERR
);
8953 void ___cleanup_io_module ___PVOID
8955 if (___io_mod
.setup
)
8957 io_module_cleanup ();/*****************************/
8959 CloseHandle (___io_mod
.abort_select
); /* ignore error */
8960 CloseHandle (___io_mod
.always_signaled
); /* ignore error */
8962 ___io_mod
.setup
= 0;
8967 /*---------------------------------------------------------------------------*/