Main loop
Created at 2017-06-30T08:30:15+09:00

TODO

  • blocking poll with timeout or non-blocking poll
    • in game, usually non-blocking poll ? (See Urho3D)
  • android looper
  • wayland
  • glib
  • libuv

Android Looper

  • Looper
  • Handler
  • MessageQueue
[ Data structure ]
(java)
Looper (thread local and own MessageQueue)
'-' MessageQueue

Handler (process local)
'-' Looper
'-' MessageQueue (this is looper's MessageQueue)

MessageQueue
'-' Message (mMessages)
  '-' Message (next)
'-' mBlocked
'-' mPtr

(cpp)
Looper
'-' mWakeEventFd
'-' mEpollFd

NativeMessageQueue < MessageQueue, < LooperCallback
'-' mLooper


[ Looper and Handler pattern ]
(Main thread)
- Looper.prepareMainLooper => prepare =>
  - new Looper =>
    - mQueue = new MessageQueue => mPtr = nativeInit =>
      - (cpp) android_os_MessageQueue_nativeInit =>
        - new NativeMessageQueue =>
          - mLooper = Looper::getForThread or new Looper =>
            - mWakeEventFd = eventfd(0, EFD_NONBLOCK | EFD_CLOEXEC)
            - rebuildEpollLocked =>
              - mEpollFd = epoll_create
              - epoll_ctl(mEpollFd, EPOLL_CTL_ADD, mWakeEventFd ..)
  - sThreadLocal.set
- someHandler = new Handler => Handler =>
  - mLooper = Looper.myLooper => sThreadLocal.get
  - mQueue = mLooper.mQueue
- Looper.loop =>
  - me = myLooper => sThreadLocal.get
  - queue = me.mQueue
  - for (;;)
    - msg = queue.next (MessageQueue.next) =>
      - for (;;)
        - nextPollTimeoutMillis = 0
        - nativePollOnce(mPtr, nextPollTimeoutMillis) =>
          - (cpp) android_os_MessageQueue_nativePollOnce =>
            - NativeMessageQueue::pollOnce =>
              - Looper::pollOnce =>
                - for (;;)
                  - pollInner =>
                    - epoll_wait(mEpollFd, eventItems, EPOLL_MAX_EVENTS, timeoutMillis)
                    - check if triggered eventItems if any
        - synchronized (this)
          - checks mMessages's head and its scheduled time
            - if the scheduled time is future, update nextPollTimeoutMillis until then
            - otherwise pop msg from mMessages and return
          - if no messages, nextPollTimeoutMillis = -1  
          - if there's not even idle handlers, mBlocked = true
        - execute idle handlers if any
    - msg.target.dispatchMessage (Handler.dispatchMessage) =>
      - handleCallback => <runnable>.run (this is posted runnable from other threads)


(other threads (sharing someHandler created in Main thread))
- someHandler.post(<runnable>) =>
  - getPostMessage =>
    - Message m = Message.obtain => new Message
    - m.callback = <runnable>
  - sendMessageDelayed => sendMessageAtTime =>
    - msg.target = this
    - enqueueMessage(mQueue, ..) => MessageQueue.enqueueMessage =>
      - synchronized (this)
        - (update mMessages linked list)
        - (there is certain condition e.g. mBlocked and mMessages was null or etc ..)
          nativeWake(mPtr) => (cpp) android_os_MessageQueue_nativeWake =>
          - NativeMessageQueue::wake => Looper::wake => write(mWakeEventFd ..)


[ Example in application ]
- Vsync, Choreographer, InputEventReceiver...

Urho3D

  • non block event poll
  • throttling (sleep) by checking exact global time