comp.lang.ada
 help / color / mirror / Atom feed
From: "Lucretia" <lucretia9@lycos.co.uk>
Subject: Possible solution to implementing task safety within wxAda, please comment ;-D
Date: 31 Oct 2005 09:37:19 -0800
Date: 2005-10-31T09:37:19-08:00	[thread overview]
Message-ID: <1130780239.573919.126650@f14g2000cwb.googlegroups.com> (raw)

I have come up with a (partial?) plan to implement task safe event
handling. There is, as far as I know, only one area where task safety
is required and that is in the triggering of events. There are two
different places an event can be triggered:

1) Inside wxWidgets, e.g. a wxButton click event (or some other
control's internal event) - this would be forwarded to a wxAda
application from the C++ glue code and a proxy event created on the Ada
side.

2) From inside wxAda, e.g. a new control derived from an wxAda type
(wx.Core.Control.Control_Type) which triggers an event on some input
action.

In both cases triggering events occurs using functions in wxEvtHandler
(wx.Base.Event_Handler.Event_Handler_Type in wxAda). So, if an event is
triggered in the main app and there exists a number of Ada tasks which
also trigger events, there could potentially be deadlock problems if
they're all sending events to the same Event_Handler_Type.

A solution could be to create a protected type which wraps around
certain wxEvtHandler_* C function wrappers. Do we need to wrap every C
function wrapper for the event handler inside this protected object?
This protected type could then be instantiated in each
Event_Handler_Type, thus the request to Event_Handler_Type's primitives
could then call the protected type. Any access to this protected type
would synchronise all requests to trigger events.

wxEvtHandler::AddPendingEvent - Asynchronous
wxEvtHandler::ProcessEvent    - Synchronous

Given a protected object in Ada, is it possible to lock on the C++ side
as well? Do we need to? Here's some code - which hasn't been tested -
which should illustrate the problem (and structure of the code) more
clearly:

<example code>
// We have to derive a new class for this type to implement virtuals
correctly - although this hasn't been shown.
class wxAdaEvtHandler : public wxEvtHandler
    {
    DECLARE_DYNAMIC_CLASS(wxAdaEvtHandler);

    public:
        wxAdaEvtHandler()
            : wxEvtHandler()
            {
            }

        virtual ~wxAdaEvtHandler()
            {
            }

        void AddPendingEvent(wxEvent& event)
            {
            // Do we need to lock here?

            wxEvtHandler::AddPendingEvent(event);

            // Do we need to unlock here?
            }

        virtual bool ProcessEvent(wxEvent& event)
            {
            // Do we need to lock here?

            wxEvtHandler::ProcessEvent(event);

            // Do we need to unlock here?
            }
    };


/* We implement the C wrappers aound the C++ class here. */
extern "C"
    {
    void wxEvtHandler_AddPendingEvent(wxAdaEvtHandler *Self, wxEvent
*Event)
        {
        Self->AddPendingEvent(*Event);
        }

    void wxEvtHandler_ProcessEvent(wxAdaEvtHandler *Self, wxEvent
*Event)
        {
        Self->AddPendingEvent(*Event);
        }
    };

package wx.Base.Event_Handler is

  type Event_Handler_Type is new wx.Base.Object.Object_Type with
private;

  procedure Add_Pending_Event(Self : in out Event_Handler_Type; Event :
in wxEvent.Event_Type);
  function Process_Event(Self : in Event_Handler_Type; Event : in
wxEvent.Event_Type) return Boolean;

private

  protected type Protected_Handler_Type is

    procedure Add_Pending_Event(Self, Event : in System.Address);
    procedure Process_Event(Self, Event : in System.Address);

  end Protected_Handler_Type;

  type Event_Handler_Type is new wx.Base.Object.Object_Type with
  record
    P : Protected_Handler_Type;
  end record;

end wx.Base.Event_Handler;


package body wx.Base.Event_Handler is

  procedure Add_Pending_Event(Self : in out Event_Handler_Type; Event :
in wxEvent.Event_Type) is

  begin

    Self.P.Add_Pending_Event(Get_wxObject(Self), Get_wxObject(Event));

  end Add_Pending_Event;


  function Process_Event(Self : in Event_Handler_Type; Event : in
wxEvent.Event_Type) return Boolean is

  begin

    Self.P.Process_Event(Get_wxObject(Self), Get_wxObject(Event));

  end Process_Event;

  protected body Protected_Handler_Type is

    procedure Add_Pending_Event(Self, Event : in System.Address) is

      procedure AddPendingEvent(Self, Event : in System.Address);
      pragma Import(C, AddPendingEvent,
"wxEvtHandler_AddPendingEvent");

    begin

      -- This call returns immediately.
      AddPendingEvent(Self, Event);

    end Add_Pending_Event;

    procedure Process_Event(Self, Event : in System.Address) is

      function ProcessEvent(Self, Event : in System.Address) return
Interfaces.C.int;
      pragma Import(C, ProcessEvent, "wxEvtHandler_ProcessEvent");

    begin

      -- This call will process the event and then return.
      ProcessEvent(Self, Event);

    end Process_Event;

  end Protected_Handler_Type;

end wx.Base.Event_Handler;
</example code>

The alternative would be to wrap each and every Event_Handler_Type
created inside a protected object which would then be called instead of
the actual instance, this I think, would be problematic.

Thanks,
Luke.




                 reply	other threads:[~2005-10-31 17:37 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed
replies disabled

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox