* UML static structure:
+----------+
| <<if>>   |---o request_accept ()
| IMAccept |---o request_connect ()  
+----------+                          +--------+
     A                    +---------|>| IMAuth |
     |                    |           +--------+
     |                    |
 +-------+           +-----------+       +--------+
 | IMSvr |<>----+----| IMUserMgr |<>-----| IMUser |
 +-------+      |    +-----------+ 1   * +--------+
    |           |
    .           |    +-------+       +--------+        +--------+
    |           +----| LEMgr |<>-----| LEBase |-.-.-.->| libiml |
    .           |    +-------+ 1   * +--------+        +--------+
    |           |
    .           |    +------------+       +---------+       +---------+
    |           +----| IMProtocol |<>-----| IMState |<>-----| ICState |
    V                +------------+ 1   * +---------+ 1   * +---------+
+-------------+               A                 A
|<<singleton>>|---o start ()  |                 |
| IMScheduler |---o stop ()   |                 +-------------------------+
+-------------+               +--+                                        |
       A                         |                                        |
       |                         |                                        |
+------------------+          +--------------+       +----------------+   |
| IMScheduler_MTPC |-.-.-.-.->| IIIMProtocol |<>-----| IMSocketListen |   |
+------------------+          +--------------+ 1   1 +----------------+   |
        \                                <>                               |
         \                                |                               |
  +-------------------------------+       +----------map {IIMPTrans*, IIIMP_IMState}
 / Make a thread per connection.  |
| Invoke thread func IMScheduler_ |
| MTPC_thread_entry ()            |
+---------------------------------+
                                          +-------+
                               +-.-.-.-.->| LEMgr |
                               |          +-------+
+-----------+                  |
| <<if>     |       +--------------+      +--------+
| IMHandler |<|-----| IMConnection |----->| IMUser |
+-----------+       +--------------+ 1  1 +--------+
                      |1   |1  |1            | 1
                      |    |   |             |
                      |    |   |             V *
                      |    |   |         +-----------+
                      |    |   +-------->| IMDesktop |
                      |    |           1 +-----------+
                      |    |
                      |    |             +-------+
                      |    +-------------| IMSvr |
    <<create>>        |                1 +-------+
 +--------------------+
 |
 |      +---------+       +-----------------+
 |      | ICState |<>-----| IMLExec_ICState |
 |      +---------+ 1   1 +-----------------+
 |          |
 |          . <<use>>
 |          |
 V *        V
+---------------+
|   <<if>>      |----o send_event ()
|   ICHandler   |----o ...
+---------------+
      A
      |
+----------------+       +--------------+
| IMInputContext |<----->| IMConnection |
+----------------+ *   1 +--------------+
    |    | 1
    .    |               +-----------+        +-----------------------+
    |    +-------------->| LEContext |-------/ One ic may corresponds |
    .                  * +-----------+      | to several LE context   | 
    |                                       +-------------------------+
    .          +-------+
    +-.-.-.-.->| LEMgr | Note: LEMgr should be a singleton?
    .          +-------+
    |
    .          +---------+
    |          | <<if>>  |       +-----------------+
    +-.-.-.-.->| IMLExec |<|-----| IMLExec_ICState |
               +---------+       +-----------------+

+------------+       +---------------+       +------------------+
| IIIMPTrans |<>-----| IMSocketTrans |<|-----| IMSocketTransTLS |
+------------+ 1   1 +---------------+       +------------------+

* Before connected:
1. IIIMProtocol::accept ()
   IIIMProtocol::restart (), initialize the private member
   IMSocketListen *pimsl.

   use pimsl to accetp a client socket, and return an IMSocketTrans
   instance, if passes the authorization, create an IIIMP_IMState
   object and return.

2. IMScheduler_MTPC::start ()
   create a pthread for this client's connection

3. IIIMProtocol::receive_and_dispatch ()
   pthread loop IMScheduler_MTPC_thread_entry call this function to
   handle client requests.

   IIIMPTrans::receive () to receive an IIIMP_message, then call 4.

4. IIIMP_IMState::dispatch ()
   if ic_id is invalid, call IMState::deliver (). Since the connection
   has not been established, the IMState::pproc_state should be null,
   so it then call IIIMP_IMState::message_proc ().

5. IIIMP_IMState::message_proc()
   in case of IM_CONNECT message, get userinfo from request, call
   IMSvr::request_connect (). This IMAccetp interface tries to
   authorize this user, if successed, create an IMConnection and
   returned as IMHandler*. Change imstate to IIIMP_IMState_Identified.

6. IIIMP_IMState_Identified::message_proc ()
   If connected clients request an operation for im instead of ic,
   (e.g., IM_CREATEIC, IM_DISCONNECT etc), this method will be
   invoked, while in this case the ic_id must be invalid.

   in case of IM_CREATEIC, call IMConnection::createic () to create an
   IMInputContext instance and returned as ICHandler*. call
   IIIMP_ICState::create(ic_id, this, pich) to create an icstate
   instance, add it to icmap, then send a reply to client.

* After connected:
1. IIIMProtocol::receive_and_dispatch ()
  
2. IMState::dispatch ()
   if ic_id is valid, from the IMState::IMShared::ICStateMap, look up
   the matched ICState, then call ICState::deliver () to handle the
   client's request or reply.

3. ICState::deliver ()
   get current ICState, and then call its message_proc ().
   IIIMP_ICState::start_request() will turn the current state to
   IIIMP_ICState_REQUESTED. While IIIMP_ICState_REQUESTED::finish ()
   will restore to previous state, and destory itself.

   if current state is requested, its message_proc () will return
   false, since it can not handle any request at that time.

   if current state is waiting, its message_proc () will see whether
   the incoming message is what it's waiting for. if not, it calls
   IIIMP_ICState::message_proc () to handle this message, so in
   waiting state will not block the normal request. or, it retrieves
   and restore to the previous back-up request state, and then call its
   dealing method. this method in trun calls get_imlexec()->execute(),
   this method execute all pending iml instructions.

   IIIMP_ICState_REQUESTED::wait ()
   IIIMP_ICState_REQUESTED::wait_aux ()
   These two methods can change the current icstate from "requested"
   to "waiting" (for the replies from client).

   IIIMP_ICState::message_proc()
   in case of IM_SETICFOCUS:
     start_request()->toggle_icfocus () [REQUESTED::toggle_focus ()]
       get_ichandler()->toggle_focus () [IMInputContext::toggle_focus ()]
         get_current_lecontext()->toggle_focus () [LEContext::toggle_focus ()]
           if_SetSCFocus () [SunIM.c: if_SetSCFocus ()]
             s->If->ifm->if_SetSCFocus () [specified LE's setfocus function]
       dealing ()
         execute remaining IML instructions (pushed by LEs)
         finish (), restore to previous state

* How does LE invoke server?
LE can not directly call server functions to send reply/messages to
client. LE calls iml methods (defined at iiimsf/lib/iml/SunIMSubr.c)
to create iml instructions, and append them to the operation list
(via iml_execute(), virtually is iml_execute_iml_wrapper() in LE.cpp).

As we mentioned early, IIIMP_ICState_REQUESTED::dealing() calls
IMLExec_ICState::execute() to process the pending instructions.

IMLExec_ICState::execute_opcode(), in turn calls imli_xxx methods,
these methods then call IIIMP_ICState_REQUESTED member functions which
actually send messages to client.

iml_make_commit_inst()/iml_execute()
               |
               | through an async flow
               V
in IMLExec_ICState::execute_opcode()
  case IMM_COMMIT:
    IMLExec_ICState::imli_commit ()
      IIIMP_ICState_REQUESTED::commit_string ()
        new an iiimp message
        send ()
          IIIMP_ICState::send ()
            IIIMP_IMState::send ()
              IIIMPTrans::send ()
                iiimf_stream_send ()
                  IIIMPTrans_write ()
                    IMSocketTrans::send () or
                    IMSocketTransTLS::send ()

* NameSpace I/O functions:
NameSpace I/O functions are passively invoked by LEs.

in each nsio function, there is a nested event dispatching loop.
Take open_ns () as an example:

   send_message = iiimp_open_ns_new (...);
   xims->send (send_message, true);

   for (;;) {
       xims->get_iiimptrans ()->receive ();
       if (opcode == IM_OPEN_NS_REPLY) {
           break;
       } else {
           xims->dispatch (...);
       }
   }

this loop is very simliar with IIIMProtocol::receive_and_dispatch.

* Misc:
ICState::send_avail_p ()
  IIIMP_ICState::state_send_available_p () { return false; }
  IIIMP_ICState_REQUESTED::state_send_available_p () { return true; }
  IIIMP_ICState_WAITING::state_send_available_p () { return false; }

-----------ICState::deliver ()--------------
if (!p->message_proc(message)) return false;
if (send_avail_p() && get_imlexec()) {
    result = get_imlexec()->execute();
}
--------------------------------------------

only when the icstate in requested, ICState::deliver () will try to
execute the buffered iml instructions. Because only in this state, the
server side (LEs) need to respond to client, and then LE may push iml
instructions in the queue.

Basicly, every branch in IIIMP_ICState::message_proc () will call
IIIMP_ICState_REQUESTED::dealing (), which actually calls
get_imlexec()->execute(). Is it a dup invoke in ICState::deliver ()?


评论:

发表一条评论:
该日志评论功能被禁用了。

This blog copyright 2009 by yongsun