3 #include <proto/alib.h>
4 #include <proto/exec.h>
6 #include <proto/utility.h>
7 #include <proto/powerpc.h>
8 #include <intuition/classusr.h>
9 #include <exec/memory.h>
10 #include <dos/dosextens.h>
11 #include <dos/dostags.h>
12 #include <proto/powerpc.h>
13 #include <powerpc/powerpc.h>
17 #include "ScalosIntern.h"
18 #include "PPCRootClass.h"
19 #include "SubRoutinesPPC.h"
20 #include "PPCThreadRootClass.h"
21 #include "MethodSenderClass.h"
23 #include "CompilerSupport.h"
26 #include "scalos_protos.h"
28 // replaces missing WarpOS functions
29 #define ObtainSemaphoreSharedPPC ObtainSemaphorePPC
30 #define AttemptSemaphoreSharedPPC AttemptSemaphorePPC
32 static char deftaskname
[] = "private_object";
35 *--------------------------- ThreadTask -------------------------------
37 * This is the taskfunction of the object-thread. It will receive the
38 * startup message and then initiate the object. After this it will go
39 * into the input loop.
43 static void SAVEDS
Thread_Task(void)
45 struct SCMSGP_Startup
*startmsg
;
47 struct MsgPortPPC
*msgport
;
48 struct TaskPPC
*owntask
= FindTaskPPC(NULL
);
51 msgport
= owntask
->tp_Msgport
;
54 while (!(startmsg
= (struct SCMSGP_Startup
*) GetMsgPPC(msgport
)))
57 threadobj
= startmsg
->threadobj
;
58 if ((startmsg
->scmsg
.returnvalue
= SC_DoMethodPPC(threadobj
, SCCM_Init
, startmsg
->taglist
)))
60 if (!(msgport
= (struct MsgPortPPC
*) getPPC(threadobj
, SCCA_MsgPort
)))
62 SC_DoMethodPPC(threadobj
, SCCM_Exit
);
63 startmsg
->scmsg
.returnvalue
= NULL
;
64 ReplyMsgPPC((struct Message
*) startmsg
);
68 ReplyMsgPPC((struct Message
*) startmsg
);
69 while (!(SC_DoMethodPPC(threadobj
, SCCM_Input
)))
75 ReplyMsgPPC((struct Message
*) startmsg
);
82 /*--------------------------- Functions --------------------------------*/
84 static ULONG
ThreadRoot_New(struct SC_Class
*cl
, Object
*obj
, struct opSet
*msg
, struct ThreadRootInst
*inst
)
86 struct SCMSGP_Startup
*startmsg
;
88 struct MsgPortPPC
*replyport
;
90 char *taskname
= (char *) &deftaskname
;
94 if (((struct SC_Class
*) obj
)->ClassName
)
95 taskname
= ((struct SC_Class
*) obj
)->ClassName
;
97 // the sender object that you get back
98 // methodsender is directly derived from root so that Object * for this
99 // object is the pointer to the beginning of its instance data
101 if (!(startmsg
= (struct SCMSGP_Startup
*) SC_AllocMsgPPC(SCMSG_STARTUP
,sizeof(struct SCMSGP_Startup
))))
105 if ((replyport
= CreateMsgPortPPC())) // only for startup msg
107 startmsg
->taglist
= msg
->ops_AttrList
;
108 SetReplyPortPPC((struct Message
*) startmsg
, replyport
);
113 if ((inst
= SC_AllocVecPPC(((struct SC_Class
*) obj
)->InstOffset
+ ((struct SC_Class
*) obj
)->InstSize
+ sizeof(struct ThreadRootInst
), MEMF_CLEAR
| MEMF_ANY
)))
115 // set class pointer for the real object that we create
117 inst
->oclass
= (struct SC_Class
*) obj
;
119 // now we can execute methods of this object
121 // get "public" handle on baseclass instance from real beginning of obj data
123 obj
= (Object
*) (((struct ThreadRootInst
*) inst
) + 1);
125 // set obj pointer of real object in msg
127 startmsg
->threadobj
= obj
;
129 // tell sender obj where to send its methods
132 if ((senderobj
= SC_NewObjectPPC(NULL
, SCC_METHODSENDER_NAME
,SCCA_MethodSender_DestObject
, obj
, TAG_DONE
)))
135 if ((proc
= CreateTaskPPCTags(TASKATTR_CODE
,Thread_Task
, TASKATTR_NAME
,taskname
, TASKATTR_STACKSIZE
,16384, TAG_DONE
)))
137 struct MsgPortPPC
*msgsendmsgport
;
139 msgsendmsgport
= proc
->tp_Msgport
;
143 PutMsgPPC(msgsendmsgport
, (struct Message
*) startmsg
); // send StartupMessage
144 while (!GetMsgPPC(replyport
))
145 WaitPortPPC(replyport
); // wait for the reply
148 // the first received message must be our startupmessage
149 if (startmsg
->scmsg
.returnvalue
)
152 DeleteMsgPortPPC(replyport
);
153 SC_FreeMsgPPC((struct SC_Message
*) startmsg
);
154 SCOCLASS(obj
)->ObjectCount
+= 1;
155 SetCache(CACHE_DCACHEFLUSH
, inst
, sizeof(struct ThreadRootInst
));
156 return((ULONG
) senderobj
);
160 SC_SetAttrsPPC(senderobj
,SCCA_MethodSender_DestObject
,NULL
,TAG_DONE
);
161 SC_DisposeObjectPPC(senderobj
);
164 DeleteMsgPortPPC(replyport
);
166 SC_FreeMsgPPC((struct SC_Message
*) startmsg
);
170 static ULONG
ThreadRoot_Dispose(struct SC_Class
*cl
, Object
*obj
, Msg msg
, struct ThreadRootInst
*inst
)
172 SC_DoMethodPPC(obj
, SCCM_Exit
);
173 SCOCLASS(obj
)->ObjectCount
-= 1;
174 SC_FreeVecPPC(myThreadRootInst(obj
));
178 /****** ThreadRoot.scalos/SCCM_Init *****************************************
184 * BOOL SC_DoMethod(obj,SCCM_Init,struct TagItem *taglist);
187 * This is the standard init function. It replaces the old OM_NEW method.
188 * The Rootclass will initialize the lists (notification list and object
189 * list) and create a messageport.
192 * taglist - the taglist for the init method attributes
195 * TRUE if the init method was successfull.
198 * The method will be called in the object that runs on a new thread.
199 * NEVER USE OM_NEW! You'll get the wrong object and instance data!
204 *****************************************************************************
207 static ULONG
ThreadRoot_Init(struct SC_Class
*cl
, Object
*obj
, struct SCCP_Init
* msg
, struct ThreadRootInst
*inst
)
209 inst
= myThreadRootInst(obj
);
211 NewList((struct List
*) &inst
->objectlist
);
212 NewList((struct List
*) &inst
->notilist
);
213 if (InitSemaphorePPC(&inst
->objectlistsem
))
215 if (InitSemaphorePPC(&inst
->notilistsem
))
217 if ((inst
->msgport
= CreateMsgPortPPC()))
220 RemSemaphorePPC(&inst
->notilistsem
);
222 RemSemaphorePPC(&inst
->objectlistsem
);
227 /****** ThreadRoot.scalos/SCCM_Exit *****************************************
233 * SC_DoMethod(obj,SCCM_Exit);
236 * This is the replacement for OM_DISPOSE. Here your object should free all
244 * SCCM_Exit will be called from the thread of the object.
249 *****************************************************************************
252 static ULONG
ThreadRoot_Exit(struct SC_Class
*cl
, Object
*obj
, Msg msg
, struct ThreadRootInst
*inst
)
254 struct MinNode
*node
;
256 inst
= myThreadRootInst(obj
);
257 ObtainSemaphorePPC(&inst
->objectlistsem
);
258 while (!(IsListEmpty((struct List
*) &inst
->objectlist
)))
260 node
= inst
->objectlist
.mlh_Head
;
261 RemovePPC((struct Node
*) node
);
262 SC_DoMethodPPC(SCBASEOBJECT(node
), OM_DISPOSE
);
264 ReleaseSemaphorePPC(&inst
->objectlistsem
);
265 ObtainSemaphorePPC(&inst
->notilistsem
);
266 FreeAllNodesPPC(&inst
->notilist
);
267 ReleaseSemaphorePPC(&inst
->notilistsem
);
268 DeleteMsgPortPPC(inst
->msgport
);
272 /****** ThreadRoot.scalos/OM_ADDMEMBER **************************************
278 * SC_DoMethod(obj,OM_ADDMEMBER,Object *childobj);
281 * Adds an object to the child list of this object.
284 * childobj - Object to add.
293 *****************************************************************************
296 static ULONG
ThreadRoot_AddMember(struct SC_Class
*cl
, Object
*obj
, struct opMember
*msg
, struct ThreadRootInst
*inst
)
298 inst
= myThreadRootInst(obj
);
300 ObtainSemaphorePPC(&inst
->objectlistsem
);
301 AddTailPPC((struct List
*) &inst
->objectlist
, (struct Node
*) &_SCOBJECT(msg
->opam_Object
)->sco_Node
);
302 ReleaseSemaphorePPC(&inst
->objectlistsem
);
306 /****** ThreadRoot.scalos/OM_REMMEMBER **************************************
312 * SC_DoMethod(obj,OM_REMMEMBER,Object *childobj);
315 * Removes an object from the child list of this object.
318 * childobj - Object to remove.
327 *****************************************************************************
330 static ULONG
ThreadRoot_RemMember(struct SC_Class
*cl
, Object
*obj
, struct opMember
*msg
, struct ThreadRootInst
*inst
)
332 inst
= myThreadRootInst(obj
);
334 ObtainSemaphorePPC(&inst
->objectlistsem
);
335 RemovePPC((struct Node
*) &_SCOBJECT(obj
)->sco_Node
);
336 ReleaseSemaphorePPC(&inst
->objectlistsem
);
340 /****** ThreadRoot.scalos/SCCM_Notify ***************************************
346 * SC_DoMethod(obj,SCCM_Notify,ULONG TriggerAttr, ULONG TriggerVal, Object *DestObj, ULONG NumArgs, ...);
349 * This method adds a notify to the notification list.
350 * If an attribute was set, the Rootclass will check the notification list
351 * for an attribute to trigger. If so and the attribute has changed and
352 * is the same as the trigger value the Rootclass will call a method in
353 * the given DestObj. Attributes in the DestObj can be set with the SCCM_Set
355 * SCCV_TriggerValue reflects the state of the attribute that triggers the
356 * destination attribute, if any.
357 * If you want to change an attribute as the result of a notification you
358 * can use SCCV_TriggerValue, which reflects the state of the source
359 * attribute TriggerAttr as the value for the destination attribute to
360 * change the attribute of the destination object to the same value.
361 * Of course the possible values of the source attribute should make sense
362 * to the destination attribute.
365 * TriggerAttr - an attribute to trigger
366 * TriggerVal - the value when the notify should be done or
367 * SCCV_EveryTime if the notify should be done when every the
368 * triggerattr was changed
369 * DestObj - destination object to do the notify method
370 * NumArgs - number of following arguments
378 *****************************************************************************
381 static ULONG
ThreadRoot_Notify(struct SC_Class
*cl
, Object
*obj
, struct SCCP_Notify
*msg
, struct ThreadRootInst
*inst
)
383 struct NotifyNode
*buffer
;
384 ULONG cpsize
= (msg
->numargs
)*sizeof(ULONG
) + sizeof(struct NotifyNode
) - 3*sizeof(ULONG
); // complete parameters length
386 inst
= myThreadRootInst(obj
);
387 ObtainSemaphorePPC(&inst
->notilistsem
);
388 if ((buffer
= (struct NotifyNode
*) AllocNodePPC(&inst
->notilist
,cpsize
)))
389 memcpy(&buffer
->TriggerAttr
, &msg
->TriggerAttr
, cpsize
- sizeof(struct MinNode
));
390 ReleaseSemaphorePPC(&inst
->notilistsem
);
394 void ThreadRoot_Set(struct SC_Class
*cl
, Object
*obj
, struct opSet
*msg
, struct ThreadRootInst
*inst
)
396 struct TagItem
*tmptaglist
= msg
->ops_AttrList
;
397 struct TagItem
**taglist
= &tmptaglist
;
399 struct NotifyNode
*node
;
406 inst
= myThreadRootInst(obj
);
407 ObtainSemaphoreSharedPPC(&inst
->notilistsem
);
408 while ((tag
= NextTagItemPPC(taglist
))) // search in taglist
410 // look for a attribute that we should trigger
411 for (node
= (struct NotifyNode
*) inst
->notilist
.mlh_Head
; node
->node
.mln_Succ
; node
= (struct NotifyNode
*) node
->node
.mln_Succ
)
413 if (tag
->ti_Tag
== node
->TriggerAttr
) // if found
415 if ( !(SC_GetAttrPPC(tag
->ti_Tag
,obj
,&tmpvalue
)) || (tag
->ti_Data
!= tmpvalue
) ) // if current attribute from object doesn`t exist or the attribute has been changed
417 /* execute only if attr-value has changed */
418 if ((node
->TriggerVal
== SCCV_EveryTime
) || (tag
->ti_Data
== node
->TriggerVal
)) // SCCV_EveryTime: notify everytime the values changes
420 if (node
->arg_method
== SCCM_Set
)
422 if (node
->arg_value
== SCCV_TriggerValue
)
423 SC_SetAttrsPPC(node
->DestObject
, node
->arg_attr
, tag
->ti_Data
, TAG_DONE
);
425 SC_SetAttrsPPC(node
->DestObject
, node
->arg_attr
, node
->arg_value
);
429 srcarray
= &node
->arg_method
;
430 if (node
->numargs
> 10)
431 destarray
= SC_AllocVecPPC(node
->numargs
* sizeof(ULONG
), MEMF_PUBLIC
);
433 destarray
= (ULONG
*) &tmparray
;
434 for (i
= 0; i
< node
->numargs
; i
++)
436 if (srcarray
[i
] == SCCV_TriggerValue
)
437 destarray
[i
] = tag
->ti_Data
;
439 destarray
[i
] = srcarray
[i
];
441 SC_DoMethodAPPC(node
->DestObject
, (Msg
) destarray
);
442 if (node
->numargs
> 10)
443 SC_FreeVecPPC(destarray
);
449 ReleaseSemaphorePPC(&inst
->notilistsem
);
452 /****** ThreadRoot.scalos/SCCM_Input ****************************************
458 * SC_DoMethod(obj,SCCM_Input);
461 * This method manages the input handling of the thread. It's a simple
462 * message loop which understands some internal messages too.
469 * If your method needs some time to be executed you should call this
470 * method from time to time to avoid locking situations so that a
471 * potential sender won`t lock because you don`t receive its message
472 * (generated from its method).
476 *****************************************************************************
478 * InternReply - checks the message before reply. If it's already a reply or
479 * it has no replyport, then it will free the message.
482 static void InternReply(struct Message
*msg
)
484 if ((msg
->mn_Node
.ln_Type
== NT_REPLYMSG
) || (!(msg
->mn_ReplyPort
)))
485 SC_FreeMsgPPC((struct SC_Message
*) msg
);
490 static ULONG
ThreadRoot_Input(struct SC_Class
*cl
, Object
*obj
, Msg msg
, struct ThreadRootInst
*inst
)
492 struct Message
*message
;
495 inst
= myThreadRootInst(obj
);
496 while ((message
= GetMsgPPC((struct MsgPortPPC
*) inst
->msgport
)))
498 if (message
->mn_Node
.ln_Type
== NT_MESSAGE
)
500 if ((msgtype
= SC_IsScalosMsgPPC(message
)))
502 if (msgtype
== SCMSG_METHOD
) // internal msg for a method
504 ((struct SC_Message
*) message
)->returnvalue
= SC_DoMethodAPPC(obj
, (Msg
) &((struct SCMSGP_Method
*) message
)->methodarg1
);
505 if (((struct SCMSGP_Method
*) message
)->methodarg1
== OM_DISPOSE
)
507 InternReply(message
);
510 InternReply(message
);
514 SC_DoMethodPPC(obj
, SCCM_MessageReceived
, message
);
515 InternReply(message
);
520 SC_DoMethodPPC(obj
, SCCM_MessageReceived
, message
);
521 ReplyMsgPPC(message
);
526 SC_DoMethodPPC(obj
, SCCM_ReplyReceived
, message
);
533 /****** ThreadRoot.scalos/SCCM_MessageReceived ******************************
536 * SCCM_MessageReceived
539 * SC_DoMethod(obj,SCCM_MessageReceived, struct Message *message);
542 * Your object will get this method if the thread has received a message
543 * that scalos doesn`t handle in SCCM_Input.
546 * message - exec message which was received by your thread
554 *****************************************************************************
557 /****** ThreadRoot.scalos/SCCM_ReplyReceived ********************************
563 * SC_DoMethod(obj,SCCM_ReplyReceived, struct Message *message);
566 * Your object will get this method if the thread has received an unknown
567 * (non scalos) message and it is a reply message. If this is your message,
568 * free the data and don't call your superclass for this method.
571 * message - exec message which was received by your thread
579 *****************************************************************************
581 static void ThreadRoot_ReplyReceived(struct SC_Class
*cl
, Object
*obj
, struct SCCP_ReplyReceived
*msg
, struct ThreadRootInst
*inst
)
583 if (SC_IsScalosMsgPPC(msg
->message
))
584 SC_FreeMsgPPC((struct SC_Message
*) msg
->message
);
587 /****** ThreadRoot.scalos/SCCM_LockObjectList *******************************
590 * SCCM_LockObjectList
593 * struct MinList *SC_DoMethod(obj,SCCM_LockObjectList, ULONG locktype);
596 * Using this method you can access the objectlist of an object. This list
597 * is fully semaphore protect.
598 * The return value can be NULL even for exclusive or shared locks, because
599 * the root class may provide a semaphore timeout in future.
602 * locktype - one for these values :
603 * SCCV_LockExclusive - for write access to the list, only one
604 * task can have a lock in the at one time
605 * SCCV_LockShared - for read access to the list, multiple
606 * tasks can have read access on list
607 * SCCV_LockAttempt - try to lock the list for a exclusiv lock,
608 * no waiting will be done
609 * SCCV_LockAttemptShared - try to lock the list for a shared
613 * The objectlist or NULL if the lock fails.
616 * If this function was successful you have to release the lock using the
617 * SCCM_UnlockObjectList method.
620 * SCCM_UnlockObjectList, OM_ADDMEMBER, OM_REMMEMBER
622 *****************************************************************************
625 static struct MinList
*ThreadRoot_LockObjectList(struct SC_Class
*cl
, Object
*obj
, struct SCCP_LockObjectList
*msg
, struct ThreadRootInst
*inst
)
627 inst
= myThreadRootInst(obj
);
628 switch (msg
->locktype
)
630 case SCCV_LockExclusive
:
631 ObtainSemaphorePPC(&inst
->objectlistsem
);
632 return(&inst
->objectlist
);
634 case SCCV_LockShared
:
635 ObtainSemaphoreSharedPPC(&inst
->objectlistsem
);
636 return(&inst
->objectlist
);
638 case SCCV_LockAttempt
:
639 if (AttemptSemaphorePPC(&inst
->objectlistsem
))
640 return(&inst
->objectlist
);
644 case SCCV_LockAttemptShared
:
645 if (AttemptSemaphoreSharedPPC(&inst
->objectlistsem
))
646 return(&inst
->objectlist
);
652 /****** ThreadRoot.scalos/SCCM_UnlockObjectList *****************************
655 * SCCM_UnlockObjectList
658 * SC_DoMethod(obj,SCCM_UnlockObjectList);
661 * Release the lock on the objectlist which was made using
662 * SCCM_LockObjectList.
671 * SCCM_LockObjectList, OM_ADDMEMBER, OM_REMMEMBER
673 *****************************************************************************
676 static void ThreadRoot_UnlockObjectList(struct SC_Class
*cl
, Object
*obj
, Msg msg
, struct ThreadRootInst
*inst
)
678 inst
= myThreadRootInst(obj
);
679 ReleaseSemaphorePPC(&inst
->objectlistsem
);
682 /* ----------------------------------------------------------------------- */
684 static ULONG
ThreadRoot_Get( struct SC_Class
*cl
, Object
*obj
, struct opGet
*msg
, struct ThreadRootInst
*inst
)
686 inst
= myThreadRootInst(obj
);
688 if (msg
->opg_AttrID
== SCCA_MsgPort
)
690 *(msg
->opg_Storage
) = (ULONG
) inst
->msgport
;
696 /* ----------------------------------------------------------------------- */
698 static ULONG
ThreadRoot_Default(struct SC_Class
*cl
, Object
*obj
, Msg msg
, struct ThreadRootInst
*inst
)
703 struct SC_MethodData PPCThreadRootMethods
[] =
705 { OM_NEW
, (ULONG
) ThreadRoot_New
, sizeof(struct opSet
), SCMDF_FULLFLUSH
, NULL
},
706 { OM_DISPOSE
, (ULONG
) ThreadRoot_Dispose
, sizeof(ULONG
), 0, NULL
},
707 { OM_SET
, (ULONG
) ThreadRoot_Set
, sizeof(struct opSet
), SCMDF_FULLFLUSH
, NULL
},
708 { OM_GET
, (ULONG
) ThreadRoot_Get
, sizeof(struct opGet
), SCMDF_FULLFLUSH
, NULL
},
709 { OM_ADDMEMBER
, (ULONG
) ThreadRoot_AddMember
, sizeof(struct opMember
), 0, NULL
},
710 { OM_REMMEMBER
, (ULONG
) ThreadRoot_RemMember
, sizeof(struct opMember
), 0, NULL
},
711 { SCCM_Init
, (ULONG
) ThreadRoot_Init
, sizeof(struct SCCP_Init
), SCMDF_FULLFLUSH
, NULL
},
712 { SCCM_Exit
, (ULONG
) ThreadRoot_Exit
, sizeof(ULONG
), 0, NULL
},
713 { SCCM_Notify
, (ULONG
) ThreadRoot_Notify
, sizeof(struct SCCP_Notify
) + sizeof(ULONG
)*32, 0, NULL
}, // maximal 32 args with notifies
714 { SCCM_Input
, (ULONG
) ThreadRoot_Input
, sizeof(ULONG
), 0, NULL
},
715 { SCCM_MessageReceived
, NULL
, sizeof(struct SCCP_MessageReceived
), 0, NULL
},
716 { SCCM_ReplyReceived
, (ULONG
) ThreadRoot_ReplyReceived
, sizeof(struct SCCP_ReplyReceived
), 0, NULL
},
717 { SCCM_LockObjectList
, (ULONG
) ThreadRoot_LockObjectList
, sizeof(struct SCCP_LockObjectList
), 0, NULL
},
718 { SCCM_UnlockObjectList
, (ULONG
) ThreadRoot_UnlockObjectList
, sizeof(ULONG
), 0, NULL
},
719 { SCMETHOD_DONE
, (ULONG
) ThreadRoot_Default
, 0, 0, NULL
}