2 Copyright © 1995-2006, The AROS Development Team. All rights reserved.
5 Desc: Unix filedescriptor/socket IO
9 #include <exec/types.h>
10 #include <exec/lists.h>
11 #include <exec/interrupts.h>
12 #include <exec/execbase.h>
13 #include <exec/semaphores.h>
14 #include <exec/memory.h>
15 #include <exec/resident.h>
16 #include <exec/alerts.h>
17 #include <exec/tasks.h>
18 #include <exec/ports.h>
19 #include <exec/nodes.h>
20 #include <utility/tagitem.h>
21 #include <utility/hooks.h>
22 #include <hidd/unixio.h>
23 #include <aros/asmcall.h>
24 #include <aros/symbolsets.h>
25 #include <hardware/intbits.h>
26 #include <hardware/custom.h>
29 #include <proto/exec.h>
30 #include <proto/oop.h>
31 #include <proto/utility.h>
32 #include <proto/alib.h>
34 #include <devices/timer.h>
37 #define timeval sys_timeval /* We don't want the unix timeval to interfere with the AROS one */
38 #include <sys/types.h>
43 #include <sys/ioctl.h>
50 #include LC_LIBDEFS_FILE
53 #include <aros/asmcall.h>
57 #include <aros/debug.h>
64 struct MemEntry nml_ME
[2];
67 static const struct newMemList MemTemplate
=
72 { { MEMF_CLEAR
|MEMF_PUBLIC
}, sizeof(struct Task
) },
78 /************************************************************************/
80 AROS_UFH5 (void, SigIO_IntServer
,
81 AROS_UFHA (ULONG
,dummy
, D0
),
82 AROS_UFHA (struct Custom
*,custom
, A0
),
83 AROS_UFHA (struct List
*,intList
,A1
),
84 AROS_UFHA (APTR
,ivCode
, A5
),
85 AROS_UFHA (struct ExecBase
*,SysBase
,A6
)
90 struct uio_data
* ud
= (struct uio_data
*) intList
;
92 Signal (ud
-> ud_WaitForIO
, SIGBREAKF_CTRL_C
);
99 static int unixio_start_timer(struct timerequest
* timerio
)
103 if (NULL
!= timerio
) {
104 timerio
->tr_node
.io_Command
= TR_ADDREQUEST
;
105 timerio
->tr_time
.tv_secs
= 0;
106 timerio
->tr_time
.tv_micro
= 250000;
108 SendIO(&timerio
->tr_node
);
118 static void WaitForIO (void)
120 struct uio_data
* ud
= FindTask(NULL
)->tc_UserData
;
124 fd_set rfds
, wfds
, efds
;
125 fd_set
* rp
, * wp
, * ep
;
126 struct sys_timeval tv
;
127 struct List waitList
;
128 struct uioMessage
* msg
, * nextmsg
;
131 pid_t my_pid
= getpid();
133 int terminals_write_counter
= 0;
134 struct MsgPort
* timer_port
= NULL
;
135 struct timerequest
* timerio
= NULL
;
138 * Since the signal was allocated by other task, but really is mine
139 * I need to allocate it here 'manually'. Otherwise the CreateMsgPort()
140 * would get the wrong signal.
142 AllocSignal(ud
->ud_Port
-> mp_SigBit
);
145 timer_port
= CreateMsgPort();
146 timerio
= (struct timerequest
*)CreateIORequest(timer_port
, sizeof(struct timerequest
));
147 OpenDevice("timer.device", UNIT_VBLANK
, &timerio
->tr_node
, 0);
152 D(bug("wfio: UnixIO.hidd ready ud=%08lx\n", ud
));
156 if (IsListEmpty (&waitList
))
158 D(bug("wfio: Waiting for message for task %s\n",ud
->ud_WaitForIO
->tc_Node
.ln_Name
));
159 WaitPort (ud
->ud_Port
);
160 D(bug("wfio: Got messages\n"));
165 kprintf("FLAGS FOR FDS: ");
166 ForeachNode (&waitList
, msg
) {
169 flags
= fcntl (msg
->fd
, F_GETFL
);
170 kprintf("fd %d: %d", msg
->fd
, flags
);
172 kprintf(" ASYNC SET, ");
174 kprintf(" ASYNC NOT SET, ");
180 D(bug("wfio: Waiting for message or signal for task %s\n",ud
->ud_WaitForIO
->tc_Node
.ln_Name
));
185 (1UL << ud
->ud_Port
->mp_SigBit
)
187 (1UL << timer_port
->mp_SigBit
)
192 if (rmask
& 1 << timer_port
-> mp_SigBit
)
195 * Must take the message from the timer port.
196 * Will be sending it again.
200 if (terminals_write_counter
> 0) {
201 //kprintf("RE STARTING TIMER! (%d)\n",terminals_write_counter);
202 unixio_start_timer(timerio
);
204 //kprintf("NOT RE STARTING TIMER!\n");
209 rmask
= Wait((1UL << ud
->ud_Port
->mp_SigBit
) | SIGBREAKF_CTRL_C
);
212 if (rmask
& 1 << ud
->ud_Port
-> mp_SigBit
)
214 D(bug("wfio: Got message\n"));
216 else if (rmask
& SIGBREAKF_CTRL_C
)
218 D(bug("wfio: Got signal\n"));
222 while ((msg
= (struct uioMessage
*)GetMsg (ud
->ud_Port
)))
224 if (msg
->mode
!= vHidd_UnixIO_Abort
)
227 D(bug("wfio: Got msg fd=%ld mode=%ld\n", msg
->fd
, msg
->mode
));
228 AddTail (&waitList
, (struct Node
*)msg
);
230 fcntl (msg
->fd
, F_SETOWN
, my_pid
);
231 flags
= fcntl (msg
->fd
, F_GETFL
);
232 fcntl (msg
->fd
, F_SETFL
, flags
| FASYNC
| O_NONBLOCK
);
234 if (msg
->mode
& vHidd_UnixIO_Write
&&
235 msg
->fd_type
& vHidd_UnixIO_Terminal
) {
236 terminals_write_counter
++;
237 if (1 == terminals_write_counter
) {
238 unixio_start_timer(timerio
);
246 ** I must look for all messages that tell me to watch on this
249 struct uioMessage
* umsg
, *_umsg
;
251 ForeachNodeSafe(&waitList
, umsg
, _umsg
)
253 if (umsg
->fd
== msg
->fd
)
256 if (umsg
->mode
& vHidd_UnixIO_Write
&&
257 umsg
->fd_type
& vHidd_UnixIO_Terminal
) {
258 terminals_write_counter
--;
260 if (0 == terminals_write_counter
) {
261 if (!CheckIO(&timerio
->tr_node
))
262 AbortIO(&timerio
->tr_node
);
263 WaitIO(&timerio
->tr_node
);
264 SetSignal(0, 1L << timer_port
->mp_SigBit
);
265 //kprintf("KIIIIILLLED!\n");
271 Remove((struct Node
*)umsg
);
272 FreeMem(umsg
, sizeof(struct uioMessage
));
275 ReplyMsg((struct Message
*)msg
);
277 } /* while (there are messages) */
287 D(bug("Waiting on fd "));
289 ForeachNode (&waitList
, msg
)
291 D(bug("%d, ", msg
->fd
));
292 if (msg
->mode
& vHidd_UnixIO_Read
)
294 FD_SET (msg
->fd
, &rfds
);
298 if (msg
->mode
& vHidd_UnixIO_Write
)
300 FD_SET (msg
->fd
, &wfds
);
304 FD_SET (msg
->fd
, &efds
);
315 errno
= 0; /* set errno to zero before select() call */
316 selecterr
= select (maxfd
+1, rp
, wp
, ep
, &tv
);
320 D(bug("wfio: got io sel=%ld err=%ld\n", selecterr
, err
));
323 if (selecterr
< 0 && err
== EINTR
)
328 ForeachNodeSafe (&waitList
, msg
, nextmsg
)
330 if (FD_ISSET (msg
->fd
, &efds
))
335 else if ((vHidd_UnixIO_Read
& msg
->mode
) &&
336 FD_ISSET (msg
->fd
, &rfds
))
340 if ( ((int (*)(int, void *))msg
->callback
)(msg
->fd
, msg
->callbackdata
) )
352 else if ((vHidd_UnixIO_Write
& msg
->mode
) &&
353 FD_ISSET (msg
->fd
, &wfds
))
357 D(bug("wfio: Reply: fd=%ld res=%ld replying to task %s on port %x\n", msg
->fd
, msg
->result
, ((struct Task
*)((struct Message
*)msg
)->mn_ReplyPort
->mp_SigTask
)->tc_Node
.ln_Name
,((struct Message
*)msg
)->mn_ReplyPort
));
359 kprintf("\tUnixIO task: Replying a message from task %s (%x) to port %x (flags : 0x%0x)\n",((struct Task *)((struct Message *)msg)->mn_ReplyPort->mp_SigTask)->tc_Node.ln_Name,((struct Message *)msg)->mn_ReplyPort->mp_SigTask,((struct Message *)msg)->mn_ReplyPort,((struct Message *)msg)->mn_ReplyPort->mp_Flags);
361 if (0 == (msg
->mode
& vHidd_UnixIO_Keep
)) {
362 Remove ((struct Node
*)msg
);
363 flags
= fcntl (msg
->fd
, F_GETFL
);
364 fcntl (msg
->fd
, F_SETFL
, flags
& ~FASYNC
);
365 ReplyMsg ((struct Message
*)msg
);
367 if ((msg
->mode
& vHidd_UnixIO_Write
) &&
368 (msg
->fd_type
& vHidd_UnixIO_Terminal
)) /* stegerg: CHECKME added vHidd_Unixio_terminal check */
370 terminals_write_counter
--;
371 if (terminals_write_counter
== 0) {
372 if (!CheckIO(&timerio
->tr_node
))
373 AbortIO(&timerio
->tr_node
);
374 WaitIO(&timerio
->tr_node
);
375 SetSignal(0, 1L << timer_port
->mp_SigBit
);
382 * Since I am supposed to keep the message
383 * I cannot use ReplyMsg() on it, because that
384 * would put it on the reply port's message port.
385 * So I am doing things 'manually' here what
386 * ReplyMsg() does internally, except for putting
387 * the message onto the message port.
389 struct MsgPort
*port
;
391 port
=((struct Message
*)msg
)->mn_ReplyPort
;
394 /* And trigger the arrival action. */
395 switch(port
->mp_Flags
&PF_ACTION
)
399 Signal((struct Task
*)port
->mp_SigTask
,1<<port
->mp_SigBit
);
403 /* Raise a software interrupt */
404 Cause((struct Interrupt
*)port
->mp_SoftInt
);
419 D(bug("wfio: Timeout sel=%ld err=%ld\n", selecterr
, err
));
424 /* This is the dispatcher for the UnixIO HIDD class. */
427 /********************
429 ********************/
430 OOP_Object
*UXIO__Root__New(OOP_Class
*cl
, OOP_Object
*o
, struct pRoot_New
*msg
)
432 EnterFunc(bug("UnixIO::New(cl=%s)\n", cl
->ClassNode
.ln_Name
));
433 D(bug("DoSuperMethod:%p\n", cl
->DoSuperMethod
));
434 o
=(OOP_Object
*)OOP_DoSuperMethod(cl
, o
, (OOP_Msg
)msg
);
438 struct UnixIOData
*id
;
441 id
= OOP_INST_DATA(cl
, o
);
442 D(bug("inst: %p, o: %p\n", id
, o
));
444 id
->uio_ReplyPort
= CreatePort (NULL
, 0);
445 if (id
->uio_ReplyPort
)
448 kprintf("\tUnixIO::New(): Task %s (%x) Replyport: %x\n",FindTask(NULL)->tc_Node.ln_Name,FindTask(NULL),id->uio_ReplyPort);
450 D(bug("Port created at %x\n",id
->uio_ReplyPort
));
451 ReturnPtr("UnixIO::New", Object
*, o
);
455 dispose_mid
= OOP_GetMethodID(IID_Root
, moRoot_Dispose
);
456 OOP_CoerceMethod(cl
, o
, (OOP_Msg
)&dispose_mid
);
458 ReturnPtr("UnixIO::New", OOP_Object
*, NULL
);
461 /***********************
462 ** UnixIO::Dispose() **
463 ***********************/
464 IPTR
UXIO__Root__Dispose(OOP_Class
*cl
, OOP_Object
*o
, OOP_Msg msg
)
466 struct UnixIOData
*id
= OOP_INST_DATA(cl
, o
);
468 if (id
-> uio_ReplyPort
)
469 DeletePort (id
->uio_ReplyPort
);
471 return OOP_DoSuperMethod(cl
, o
, msg
);
474 /*********************
476 *********************/
477 IPTR
UXIO__Hidd_UnixIO__Wait(OOP_Class
*cl
, OOP_Object
*o
, struct uioMsg
*msg
)
480 // struct UnixIOData *id = OOP_INST_DATA(cl, o);
481 struct uioMessage
* umsg
= AllocMem (sizeof (struct uioMessage
), MEMF_CLEAR
|MEMF_PUBLIC
);
482 struct MsgPort
* port
= CreatePort(NULL
, 0);
483 struct uio_data
*ud
= UD(cl
);
487 port
->mp_Flags
= PA_SIGNAL
;
488 port
->mp_SigTask
= FindTask (NULL
);
490 umsg
->Message
.mn_ReplyPort
= port
;
491 umsg
->fd
= ((struct uioMsg
*)msg
)->um_Filedesc
;
492 umsg
->fd_type
= vHidd_UnixIO_Socket
;
493 umsg
->mode
= ((struct uioMsg
*)msg
)->um_Mode
;
494 umsg
->callback
= ((struct uioMsg
*)msg
)->um_CallBack
;
495 umsg
->callbackdata
= ((struct uioMsg
*)msg
)->um_CallBackData
;
497 D(bug("UnixIO::Wait() Sending msg fd=%ld mode=%ld to port %x\n", umsg
->fd
, umsg
->mode
, ud
->ud_Port
));
500 kprintf("\tUnixIO::Wait() Task %s (%x) waiting on port %x\n",FindTask(NULL)->tc_Node.ln_Name,FindTask(NULL),port);
502 PutMsg (ud
->ud_Port
, (struct Message
*)umsg
);
508 D(bug("Get msg fd=%ld mode=%ld res=%ld\n", umsg
->fd
, umsg
->mode
, umsg
->result
));
509 retval
= umsg
->result
;
515 FreeMem (umsg
, sizeof (struct uioMessage
));
520 /************************
521 ** UnixIO::AsyncIO() **
522 ************************/
523 IPTR
UXIO__Hidd_UnixIO__AsyncIO(OOP_Class
*cl
, OOP_Object
*o
, struct uioMsgAsyncIO
*msg
)
526 struct uioMessage
* umsg
= AllocMem (sizeof (struct uioMessage
), MEMF_CLEAR
|MEMF_PUBLIC
);
527 struct MsgPort
* port
= msg
->um_ReplyPort
;
528 struct uio_data
*ud
= UD(cl
);
532 /* nlorentz: What action should be taken on reply of this message
533 should be the choice of the caller. (The caller might want
534 a signal instead of a softint)
536 port->mp_Flags = PA_SOFTINT;
540 umsg
->Message
.mn_ReplyPort
= port
;
541 umsg
->fd
= ((struct uioMsg
*)msg
)->um_Filedesc
;
542 umsg
->fd_type
= ((struct uioMsg
*)msg
)->um_Filedesc_Type
;
543 umsg
->mode
= ((struct uioMsg
*)msg
)->um_Mode
;
544 umsg
->callback
= NULL
;
545 umsg
->callbackdata
= NULL
;
547 D(bug("Sending msg fd=%ld mode=%ld to port %x\n", umsg
->fd
, umsg
->mode
, ud
->ud_Port
));
550 ** Just send the message and leave
551 ** When the message arrives on the port the user must free
554 PutMsg (ud
->ud_Port
, (struct Message
*)umsg
);
564 /*****************************
565 ** UnixIO::AbortAsyncIO() **
566 *****************************/
567 VOID
UXIO__Hidd_UnixIO__AbortAsyncIO(OOP_Class
*cl
, OOP_Object
*o
, struct uioMsgAbortAsyncIO
*msg
)
569 struct uioMessage
* umsg
= AllocMem (sizeof (struct uioMessage
), MEMF_CLEAR
|MEMF_PUBLIC
);
570 struct uio_data
*ud
= UD(cl
);
571 struct MsgPort
* port
= CreatePort(NULL
, 0);
575 umsg
->Message
.mn_ReplyPort
= port
;
576 umsg
->fd
= ((struct uioMsg
*)msg
)->um_Filedesc
;
577 umsg
->mode
= vHidd_UnixIO_Abort
;
579 PutMsg (ud
->ud_Port
, (struct Message
*)umsg
);
587 FreeMem (umsg
, sizeof (struct uioMessage
));
593 /*****************************
594 ** UnixIO::OpenFile() **
595 *****************************/
596 APTR
UXIO__Hidd_UnixIO__OpenFile(OOP_Class
*cl
, OOP_Object
*o
, struct uioMsgOpenFile
*msg
)
598 APTR retval
= (APTR
)open((const char *)msg
->um_FileName
, (int)msg
->um_Flags
, (int)msg
->um_Mode
);
600 if (msg
->um_ErrNoPtr
) *msg
->um_ErrNoPtr
= errno
;
605 /*****************************
606 ** UnixIO::CloseFile() **
607 *****************************/
608 VOID
UXIO__Hidd_UnixIO__CloseFile(OOP_Class
*cl
, OOP_Object
*o
, struct uioMsgCloseFile
*msg
)
610 if (msg
->um_FD
!= (APTR
)-1) close((int)msg
->um_FD
);
611 if (msg
->um_ErrNoPtr
) *msg
->um_ErrNoPtr
= errno
;
614 /*****************************
615 ** UnixIO::ReadFile() **
616 *****************************/
617 IPTR
UXIO__Hidd_UnixIO__ReadFile(OOP_Class
*cl
, OOP_Object
*o
, struct uioMsgReadFile
*msg
)
619 IPTR retval
= (IPTR
)-1;
621 if (msg
->um_FD
!= (APTR
)-1)
625 retval
= (IPTR
)read((int)msg
->um_FD
, (void *)msg
->um_Buffer
, (size_t)msg
->um_Count
);
626 //kprintf(" UXIO__Hidd_UnixIO__ReadFile[%04ld]: retval %d errno %d buff %x count %d\n", count++, retval, errno, msg->um_Buffer, msg->um_Count);
628 if (msg
->um_ErrNoPtr
) break;
630 } while(((int)errno
== EINTR
) || ((int)errno
== EAGAIN
));
633 if (msg
->um_ErrNoPtr
) *msg
->um_ErrNoPtr
= errno
;
635 //if ((int)retval == -1) kprintf("UXIO__Hidd_UnixIO__ReadFile: errno %d buff %x count %d\n", errno, msg->um_Buffer, msg->um_Count);
640 /*****************************
641 ** UnixIO::WriteFile() **
642 *****************************/
643 IPTR
UXIO__Hidd_UnixIO__WriteFile(OOP_Class
*cl
, OOP_Object
*o
, struct uioMsgWriteFile
*msg
)
645 IPTR retval
= (IPTR
)-1;
647 if (msg
->um_FD
!= (APTR
)-1)
651 retval
= (IPTR
)write((int)msg
->um_FD
, (const void *)msg
->um_Buffer
, (size_t)msg
->um_Count
);
652 //kprintf(" UXIO__Hidd_UnixIO__WriteFile[%04ld]: retval %d errno %d buff %x count %d\n", count++, retval, errno, msg->um_Buffer, msg->um_Count);
654 if (msg
->um_ErrNoPtr
) break;
656 } while(((int)retval
< 1) && (((int)errno
== EINTR
) || ((int)errno
== EAGAIN
) || (errno
== 0)));
659 if (msg
->um_ErrNoPtr
) *msg
->um_ErrNoPtr
= errno
;
661 //if ((int)retval == -1) kprintf("UXIO__Hidd_UnixIO__WriteFile: errno %d buff %x count %d\n", errno, msg->um_Buffer, msg->um_Count);
666 /*****************************
667 ** UnixIO::IOControlFile() **
668 *****************************/
669 IPTR
UXIO__Hidd_UnixIO__IOControlFile(OOP_Class
*cl
, OOP_Object
*o
, struct uioMsgIOControlFile
*msg
)
671 IPTR retval
= (IPTR
)-1;
673 if (msg
->um_FD
!= (APTR
)-1)
675 retval
= (IPTR
)ioctl((int)msg
->um_FD
, (int)msg
->um_Request
, msg
->um_Param
);
678 if (msg
->um_ErrNoPtr
) *msg
->um_ErrNoPtr
= errno
;
683 /* This is the initialisation code for the HIDD class itself. */
685 static int UXIO_Init(LIBBASETYPEPTR LIBBASE
)
687 struct Task
* newtask
,
688 * task2
= NULL
; /* keep compiler happy */
689 struct newMemList nml
;
691 struct Interrupt
* is
;
693 LIBBASE
->uio_csd
.ud_Port
= CreatePort (NULL
, 0);
694 if(LIBBASE
->uio_csd
.ud_Port
== NULL
)
696 /* If you are not running from ROM, don't use Alert() */
697 Alert(AT_DeadEnd
| AG_NoMemory
| AN_Unknown
);
704 The original stack size was 8192, however some emulated systems
705 require a large stack during signal handlers. FreeBSD in fact
706 says that it requires 8192 just FOR the signal handler. I have
707 changed this to AROS_STACKSIZE for that reason.
709 nml
.nml_ME
[1].me_Length
= AROS_STACKSIZE
;
711 if (NewAllocEntry((struct MemList
*)&nml
, &ml
, NULL
))
713 newtask
= ml
->ml_ME
[0].me_Addr
;
715 newtask
->tc_Node
.ln_Type
= NT_TASK
;
716 newtask
->tc_Node
.ln_Pri
= 30;
717 newtask
->tc_Node
.ln_Name
= "UnixIO.task";
719 newtask
->tc_SPReg
= (APTR
)((ULONG
)ml
->ml_ME
[1].me_Addr
+ AROS_STACKSIZE
);
720 newtask
->tc_SPLower
= ml
->ml_ME
[1].me_Addr
;
721 newtask
->tc_SPUpper
= newtask
->tc_SPReg
;
723 newtask
->tc_UserData
= &LIBBASE
->uio_csd
;
725 NEWLIST (&newtask
->tc_MemEntry
);
726 AddHead (&newtask
->tc_MemEntry
, (struct Node
*)ml
);
728 task2
= (struct Task
*)AddTask (newtask
, WaitForIO
, 0);
730 if (SysBase
->LibNode
.lib_Version
>36 && !task2
)
741 /* If you are not running from ROM, don't use Alert() */
742 Alert(AT_DeadEnd
| AG_NoMemory
| AN_Unknown
);
746 LIBBASE
->uio_csd
.ud_WaitForIO
= task2
;
748 LIBBASE
->uio_csd
.ud_Port
->mp_Flags
= PA_SIGNAL
;
749 LIBBASE
->uio_csd
.ud_Port
->mp_SigTask
= task2
;
751 is
=(struct Interrupt
*)AllocMem(sizeof(struct Interrupt
),MEMF_PUBLIC
);
754 Alert(AT_DeadEnd
| AG_NoMemory
| AN_Unknown
);
757 is
->is_Code
=(void (*)())&SigIO_IntServer
;
758 is
->is_Data
=(APTR
)&LIBBASE
->uio_csd
;
759 SetIntVector(INTB_DSKBLK
,is
);
764 ADD2INITLIB(UXIO_Init
, 0)