Upstream version 9.38.204.0
[platform/framework/web/crosswalk.git] / src / xwalk / tizen / browser / media / murphy_mainloop.cc
1 // Copyright (c) 2014 Intel Corporation. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "xwalk/tizen/browser/media/murphy_mainloop.h"
6
7 #include <errno.h>
8 #include <murphy/common/macros.h>
9 #include <murphy/common/log.h>
10 #include <murphy/common/mm.h>
11 #include <sys/socket.h>
12
13 #include "base/message_loop/message_loop.h"
14 #include "base/message_loop/message_pump_libevent.h"
15 #include "content/public/browser/browser_thread.h"
16
17 //
18 // The Murphy resource libraries don't have interfaces that would allow one
19 // to take externally care of the IPC necessary for communicating with the
20 // server (the policy decision making entity). Instead these libraries always
21 // operate within the context of a Murphy mainloop abstraction which by design
22 // can be set up to be pumped by an external event loop. The MurphyMainloop
23 // class below creates a Murphy mainloop and takes care of the details of
24 // adapting it to be pumped by the local MessageLoop infrastructure.
25 //
26 // The Murphy mainloop needs abstractions for I/O watches, timers, and deferred
27 // callbacks from the hosting environment. If necessary it can get along with
28 // just I/O watches and timers and emulate deferred callbacks by low-delay
29 // timers. Murphy needs timers to be both cancellable and modifiable and it
30 // deferred callbacks that can be disabled and re-enabled.
31 //
32 // The available infrastructure here offers the basic building blocks for all of
33 // these but none of them are a perfect fit. Here is the summary of the tweaks
34 // we need (in the hope) to get the Murphy mainloop running:
35 //
36 // 1) You can only do async I/O in the content::BrowserThread::IO thread.
37 //
38 //    We're running in content::BrowserThread::UI so we can't manipulate
39 //    FileDescriptorWatchers there. To overcome this we need to relay all
40 //    operations on FileDescriptorWatchers to content::BrowserThread::IO
41 //    by PostTask. This will result in getting all the I/O events delivered
42 //    to content::BrowserThread::IO. However, since we don't want to set up
43 //    a (potentially) complex locking scheme to protect access to the mainloop
44 //    we also relay FileDescriptorWatcher notifications back to the UI thread
45 //    for processing. Finally to make sure there are no pending events in
46 //    flight by the time we destroy an I/O watch we essentially drive the
47 //    destructor through a full UI -> IO -> UI thread relay.
48 //
49 // 2) FileDescriptorWatchers don't have HUP events.
50 //
51 //    As a POSIX-specific hack we MSG_PEEK and generate a syntetic HUP event
52 //    if we got 0 bytes.
53 //
54 // 3) You can't cancel a PostTask'd or PostDelayedTask'd task.
55 //
56 //    This prevents us from having a straightforward mapping of deferred
57 //    callbacks and timers to these. To overcome this we use a 'timeout finger-
58 //    print' which is used to ignore timeout callbacks that should have been
59 //    cancelled if only there was a mechanism for it. The fingerprint in simply
60 //    a monotonically increasing integer which is stored in the timer and also
61 //    associated with a pending timeout. Whenever the timer is reconfigured
62 //    (delay updated, or timer disabled) the fingerpring is updated. Timeout
63 //    callbacks with mismatching fingerprints are ignored.
64 //
65 // Originally we simply scheduled a task from the I/O thread to the UI thread
66 // for reading the pending epoll events there. But since poll/select is level-
67 // triggered by default this caused a large amount of messages before the
68 // scheduler got around to run the UI thread an read the events. Therefore now
69 // the Murphy mainloop has been opened up for doing the actual event retrieval
70 // externally to better support pumping it from xwalk. This now starts to be
71 // hairier than I'm comfortable with... I think it'd be a better idea to run
72 // the mainloop fully in the I/O thread, have the resource sets live in the I/O
73 // thread also and have proxy object for them attached to the media backend
74 // obejcts which would send requests and receive notifications to/from the
75 // resource sets. We could avoid most of the threading related compliations
76 // for pumping the mainloop...
77 //
78 // Additionally to the basic mainloop adaptation we also set up the Murphy
79 // debugging and logging infrastructure to use the native logging infra as
80 // a backend. You can control the Murphy logging and debugging by two
81 // environment variables:
82 //
83 //    XWALK_MURPHY_LOG:
84 //        A comma separated list of log levels, defaults to 'info,warning,error'
85 //
86 //    XWALK_MURPHY_DEBUG:
87 //        A comma-separated list of Murphy debug sites, for instance
88 //        '@mainloop.c,@resource.c,mrp_resource_set_create'. Setting this to
89 //        '*' will turn all debug sites on.
90 //
91
92
93 // Environment variable names to used to control debugging and logging
94 #define ENVVAR_DBG "XWALK_MURPHY_DEBUG"
95 #define ENVVAR_LOG "XWALK_MURPHY_LOG"
96
97 namespace {
98
99 static void xwalklogger(void* data, mrp_log_level_t level, const char* file,
100     int line, const char* func, const char* format,
101     va_list ap) {
102   va_list cp;
103   char msg[1024], locbuf[1024];
104   const char* loc;
105
106   MRP_UNUSED(data);
107   MRP_UNUSED(file);
108   MRP_UNUSED(line);
109
110   va_copy(cp, ap);
111
112   if (level != MRP_LOG_DEBUG) {
113     loc = "";
114   } else {
115     snprintf(locbuf, sizeof(locbuf), "[%s] ", func ? func : "<unknown>");
116     loc = locbuf;
117   }
118
119   if (vsnprintf(msg, sizeof(msg), format, cp) < (ssize_t)sizeof(msg)) {
120     switch (level) {
121       case MRP_LOG_INFO:    LOG(INFO)    << loc << msg; break;
122       case MRP_LOG_WARNING: LOG(WARNING) << loc << msg; break;
123       case MRP_LOG_ERROR:   LOG(ERROR)   << loc << msg; break;
124       case MRP_LOG_DEBUG:  DLOG(INFO)    << loc << msg; break;
125       default:                                          break;
126     }
127   }
128
129   va_end(cp);
130 }
131
132 // Helper function to check if we have a pending HUP on an fd.
133 static int pending_hup(int fd) {
134   char buf;
135   int  len, saved_errno;
136
137   saved_errno = errno;
138   len = recv(fd, &buf, 1, MSG_PEEK);
139   errno = saved_errno;
140
141   return len == 0;
142 }
143
144 }  // namespace
145
146 namespace tizen {
147
148 // An I/O watch abstraction for Murphy mainloop integration.
149 //
150 // As stated above, FileDescriptorWatcher's can only be manipulated
151 // in BrowserThread::IO. As we execute in BrowserThread::UI we need
152 // to relay watch manipulation operations to the I/O thread and
153 // relay events back to the UI thread.
154 class IoWatch : public base::MessagePumpLibevent::Watcher {
155  public:
156   // Constructor. Saves context and relays the watch setup to the I/O thread.
157   IoWatch(MurphyMainloop* mainloop, int fd, mrp_io_event_t events,
158       void (*cb)(void* glue_data, void* id, int fd, mrp_io_event_t events,
159       void* user_data), void* user_data)
160       : mainloop_(mainloop),
161         fd_(fd),
162         events_(events),
163         cb_(cb),
164         user_data_(user_data),
165         dead_(false) {
166     content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
167         base::Bind(&IoWatch::StartWatch,
168         base::Unretained(this)));
169   }
170
171   // Request destruction. Mark dead, relay watch cleanup to the I/O thread.
172   // The destruction sequence is finished once StopWatch relays WatchStopped
173   // back to the UI thread.
174   void Delete() {
175     if (dead_)
176       return;
177     else
178       dead_ = true;
179
180     content::BrowserThread::PostTask(content::BrowserThread::IO, FROM_HERE,
181         base::Bind(&IoWatch::StopWatch,
182         base::Unretained(this)));
183   }
184
185  private:
186   // Perform watch setup. Run in the I/O thread.
187   void StartWatch() {
188     base::MessageLoopForIO::Mode mode;
189
190     if (events_ & (MRP_IO_EVENT_IN | MRP_IO_EVENT_OUT))
191       mode = base::MessageLoopForIO::WATCH_READ_WRITE;
192     else if (events_ & MRP_IO_EVENT_IN)
193       mode = base::MessageLoopForIO::WATCH_READ;
194     else if (events_ & MRP_IO_EVENT_OUT)
195       mode = base::MessageLoopForIO::WATCH_WRITE;
196     else
197       mode = base::MessageLoopForIO::WATCH_READ;  // Hmm... not quite right.
198
199     const bool success = base::MessageLoopForIO::current()->WatchFileDescriptor(
200         fd_, true, mode, &w_, this);
201     CHECK(success) << "Failed to add I/O watch for fd " << fd_;
202   }
203
204   // Perform watch cleanup. Run in I/O thread.
205   void StopWatch() {
206     if (dead_)
207       return;
208     w_.StopWatchingFileDescriptor();
209
210     content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
211         base::Bind(&IoWatch::WatchStopped,
212         base::Unretained(this)));
213   }
214
215   // Finish the destruction sequence by self-deleting. Run in UI thread.
216   void WatchStopped() {
217     delete this;
218   }
219
220   // Watch readability event handler. Run in I/O thread. Relays dispatching
221   // to UI thread.
222   virtual void OnFileCanReadWithoutBlocking(int fd) OVERRIDE {
223     if (dead_)
224       return;
225
226     mainloop_->Poll(this);
227
228     content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
229         base::Bind(&IoWatch::DispatchReadable,
230         base::Unretained(this)));
231   }
232
233   // Watch writability event handler. Run in I/O thread. Relays dispatching
234   // to UI thread.
235   virtual void OnFileCanWriteWithoutBlocking(int fd) OVERRIDE {
236     if (dead_)
237       return;
238
239     content::BrowserThread::PostTask(content::BrowserThread::UI, FROM_HERE,
240         base::Bind(&IoWatch::DispatchWritable,
241         base::Unretained(this)));
242   }
243
244   // Dispatch readability events the the mainloop.
245   void DispatchReadable() {
246     mrp_io_event_t events;
247     if (dead_)
248       return;
249
250     if ((events_ & MRP_IO_EVENT_HUP) && pending_hup(fd_))
251       events = MRP_IO_EVENT_HUP;
252     else
253       events = MRP_IO_EVENT_IN;
254
255     mrp_debug("dispatching crosswalk event 0x%x for fd %d", events, fd_);
256     cb_(reinterpret_cast<void*>(mainloop_), reinterpret_cast<void*>(this),
257         fd_, events, user_data_);
258   }
259
260   // Dispatch writability events the the mainloop.
261   void DispatchWritable() {
262     mrp_io_event_t events;
263     if (dead_)
264       return;
265
266     events = MRP_IO_EVENT_OUT;
267     mrp_debug("dispatching crosswalk event 0x%x for fd %d", events, fd_);
268     cb_(reinterpret_cast<void*>(mainloop_), reinterpret_cast<void*>(this),
269         fd_, events, user_data_);
270   }
271
272   // Associated mainloop data: fd, event mask, callback, and user data.
273   MurphyMainloop* mainloop_;
274   int fd_;
275   mrp_io_event_t events_;
276   void (*cb_)(void* glue_data, void* id, int fd, mrp_io_event_t events,
277       void* user_data);
278   void* user_data_;
279
280   // FileDescriptorWatcher we use for I/O monitoring
281   base::MessagePumpLibevent::FileDescriptorWatcher w_;
282
283   // flag used to mark initiated destruction sequence
284   bool dead_;
285
286   // A self-destructing object, so we have a private destructor
287   virtual ~IoWatch() {
288     mrp_debug("Destructing I/O watch");
289   }
290 };
291
292 // A Timer abstraction for Murphy mainloop integration.
293 //
294 // Since posted tasks cannot be cancelled, we use the stamped Timeout
295 // object to filter out callbacks for timers that have been cancelled
296 // (or reconfigured).
297 class Timer;
298
299 class Timeout : public base::RefCounted<Timeout> {
300  public:
301   explicit Timeout(Timer* t)
302       : timer_(t),
303         stamp_(0),
304         pending_(false) {
305     // Release upon timer destruction. We need to keep this object around
306     // until then.
307     AddRef();
308   }
309
310   // Clear Timeout for destruction. After this point all events are ignored.
311   // We're just waiting for the last reference to be Release()'d which is
312   // immediate if we have no pending timeouts. Otherwise it ought to happen
313   // once the last timeout has expired.
314   void Delete() {
315     timer_ = NULL;
316     Release();
317   }
318
319   // Arm or rearm the timeout with the given delay.
320   void Arm(int delay) {
321     base::TimeDelta delta(base::TimeDelta::FromMilliseconds(delay));
322     InvalidatePending();
323     content::BrowserThread::PostDelayedTask(content::BrowserThread::UI,
324         FROM_HERE,
325         base::Bind(&Timeout::Expired,
326         this, stamp_), delta);
327
328     pending_ = true;
329   }
330
331   // Disable timeouts.
332   void Disable() {
333     InvalidatePending();
334   }
335
336  private:
337   // Invalidate any possible pending Timeouts.
338   inline void InvalidatePending() {
339     if (pending_)
340       stamp_++;
341   }
342
343   // Timeout handler callback. Filter cancelled timeouts, deliver valid
344   // timeouts to the parent Timer.
345   void Expired(unsigned int stamp);
346
347   ~Timeout() {
348     mrp_debug("destructing Timeout %p", this);
349   }
350
351   // We're refcounted and have a private destructor...
352   friend class base::RefCounted<Timeout>;
353
354   // Timer we're serving.
355   Timer* timer_;
356
357   // Fingerprint stamp.
358   unsigned int stamp_;
359
360   // Flag to mark if we have pending timeouts.
361   bool pending_;
362 };
363
364 class Timer {
365  public:
366   Timer(MurphyMainloop* mainloop, int delay,
367       void (*cb)(void* glue_data, void* id, void* user_data),
368       void* user_data)
369       : mainloop_(mainloop),
370         cb_(cb),
371         user_data_(user_data),
372         delay_(delay),
373         enabled_(true),
374         timeout_(NULL) {
375     timeout_ = new Timeout(this);
376     ReArm();
377   }
378
379   // Upon timer destruction, initiate timeout destruction sequence and release
380   // its initial reference.
381   ~Timer() {
382     timeout_->Delete();
383   }
384
385   // Change timer delay.
386   void SetDelay(int delay) {
387     delay_ = delay;
388     ReArm();
389   }
390
391   // Enable timer.
392   void Enable() {
393     if (!enabled_) {
394       enabled_ = true;
395       ReArm();
396     }
397   }
398
399   // Disable timer.
400   void Disable() {
401     enabled_ = false;
402     timeout_->Disable();
403   }
404
405  private:
406   // Re-arm the timer with the current delay if it is enabled.
407   void ReArm() {
408     if (!enabled_ || delay_ == -1)
409       return;
410
411     mrp_debug("rearming timer %p (delay %d)", this, delay_);
412
413     timeout_->Arm(delay_);
414   }
415
416   // Timeout handler callback.
417   void DispatchTimer() {
418     if (enabled_) {
419       mrp_debug("dispatching crosswalk timeout event %p", this);
420       cb_(reinterpret_cast<void*>(mainloop_), reinterpret_cast<void*>(this),
421           user_data_);
422     }
423
424     if (enabled_)
425       ReArm();
426   }
427
428  private:
429   // Let Timeout invoke DispatchTimer.
430   friend class Timeout;
431
432   // Associated mainloop data: timer callback and user data.
433   MurphyMainloop* mainloop_;
434   void (*cb_)(void* glue_data, void* id, void* user_data);
435   void* user_data_;
436
437   // Our timeout in milliseconds.
438   int delay_;
439
440   // Whether we're enabled.
441   bool enabled_;
442
443   // Our associated timeout.
444   Timeout* timeout_;
445 };
446
447 void Timeout::Expired(unsigned int stamp) {
448   if (timer_ == NULL || stamp != stamp_)
449     return;
450
451   pending_ = false;
452
453   timer_->DispatchTimer();
454 }
455
456 MurphyMainloop::MurphyMainloop(const char* log, const char* debug)
457     : mainloop_(NULL),
458       poll_id_(NULL) {
459   mrp_list_init(&poll_q_);
460   setupLogger(log, debug);
461
462   CHECK(setupMainloop());
463 }
464
465 MurphyMainloop::~MurphyMainloop() {
466   mrp_debug("destroying MurphyMainloop");
467   mrp_mainloop_destroy(mainloop_);
468 }
469
470
471 // Crosswalk mainloop abstraction operations
472 void* MurphyMainloop::AddIo(void* glue_data, int fd, mrp_io_event_t events,
473     void (*cb)(void* glue_data, void* id, int fd, mrp_io_event_t events,
474     void* user_data), void* user_data) {
475
476   MurphyMainloop* self = static_cast<MurphyMainloop*>(glue_data);
477
478   CHECK(self->poll_id_ == NULL);
479
480   self->poll_id_ = new IoWatch(self, fd, events, cb, user_data);
481
482   mrp_debug("added I/O Watch %p for fd %d (glue_data: %p)", self->poll_id_, fd,
483             glue_data);
484
485   return self->poll_id_;
486 }
487
488 // static
489 void MurphyMainloop::DelIo(void* glue_data, void* id) {
490   IoWatch* w = static_cast<IoWatch*>(id);
491
492   mrp_debug("deleting I/O Watch %p", id);
493   w->Delete();
494 }
495
496
497 extern "C" {
498   typedef struct {
499     mrp_list_hook_t hook;
500     void* buf;
501     size_t size;
502   } pollq_data_t;
503 }
504
505
506 void MurphyMainloop::Poll(void* id) {
507   pollq_data_t* item;
508
509   mrp_debug("polling pending epoll events for the mainloop (id: %p)", id);
510
511 #if 0
512   CHECK(poll_id_ == id);
513   CHECK(poll_events_);
514 #else
515   if (poll_id_ != id || !poll_events_)
516     return;
517 #endif
518
519   item = reinterpret_cast<pollq_data_t *>(mrp_allocz(sizeof(*item)));
520
521   if (item == NULL)
522     return;
523
524   mrp_list_init(&item->hook);
525   item->size = poll_events_(id, mainloop_, &item->buf);
526
527   poll_lock_.Acquire();
528   mrp_list_append(&poll_q_, &item->hook);
529   poll_lock_.Release();
530 }
531
532
533 // static
534 size_t MurphyMainloop::PollIo(void* glue_data,
535     void* id, void* buf, size_t size) {
536   MurphyMainloop* self = static_cast<MurphyMainloop*>(glue_data);
537   pollq_data_t* item;
538
539   mrp_debug("dispatching epoll events to the mainloop (id: %p)", id);
540
541 #if 0
542   CHECK(self->poll_id_ == id);
543 #else
544   if (self->poll_id_ != id)
545     return 0;
546 #endif
547
548   self->poll_lock_.Acquire();
549   if (!mrp_list_empty(&self->poll_q_)) {
550     item = mrp_list_entry(self->poll_q_.next, pollq_data_t, hook);
551     mrp_list_delete(&item->hook);
552   } else {
553     item = NULL;
554   }
555
556   self->poll_lock_.Release();
557
558   if (item != NULL) {
559     CHECK(size >= item->size);
560
561     size = item->size;
562     memcpy(buf, item->buf, size);
563
564     mrp_free(item);
565   } else {
566     size = 0;
567   }
568
569   return size;
570 }
571
572 // static
573 void* MurphyMainloop::AddTimer(void* glue_data, unsigned int msecs,
574     void (*cb)(void* glue_data, void* id, void* user_data),
575     void* user_data) {
576   MurphyMainloop* self = static_cast<MurphyMainloop*>(glue_data);
577   mrp_debug("adding Timer with %u msecs, %p user data", msecs, user_data);
578
579   return new Timer(self, static_cast<int>(msecs), cb, user_data);
580 }
581
582 // static
583 void MurphyMainloop::DelTimer(void* glue_data, void* id) {
584   Timer* t = reinterpret_cast<Timer*>(id);
585   MRP_UNUSED(glue_data);
586
587   mrp_debug("deleting Timer %p", id);
588   delete t;
589 }
590
591 // static
592 void MurphyMainloop::ModTimer(void* glue_data, void* id, unsigned int msecs) {
593   Timer* t = reinterpret_cast<Timer*>(id);
594   MRP_UNUSED(glue_data);
595
596   mrp_debug("modifying Timer %p to %u msecs", t, msecs);
597   t->SetDelay(msecs);
598 }
599
600 // static
601 void* MurphyMainloop::AddDefer(void* glue_data,
602     void (*cb)(void* glue_data, void* id, void* user_data),
603     void* user_data) {
604   mrp_debug("adding deferred callback (cb:%p, user data:%p)", cb, user_data);
605   return AddTimer(glue_data, 0, cb, user_data);
606 }
607
608 // static
609 void MurphyMainloop::DelDefer(void* glue_data, void* id) {
610   MRP_UNUSED(glue_data);
611
612   mrp_debug("deleting deferred callback %p", id);
613
614   DelTimer(glue_data, id);
615 }
616
617 // static
618 void MurphyMainloop::ModDefer(void* glue_data, void* id, int enabled) {
619   MRP_UNUSED(glue_data);
620   Timer* t = reinterpret_cast<Timer*>(id);
621
622   mrp_debug("%sabling deferred callback %p", enabled ? "en" : "dis", id);
623
624   if (enabled)
625     t->Enable();
626   else
627     t->Disable();
628 }
629
630 // static
631 void MurphyMainloop::Unregister(void* data) {
632   MRP_UNUSED(data);
633
634   mrp_debug("unrgistering mainloop with data %p", data);
635 }
636
637 bool MurphyMainloop::setupMainloop() {
638   mainloop_ = mrp_mainloop_create();
639   mrp_set_io_event_mode(mainloop_, MRP_IO_TRIGGER_EDGE);
640
641   static mrp_superloop_ops_t ops = {
642     &MurphyMainloop::AddIo,
643     &MurphyMainloop::DelIo,
644     &MurphyMainloop::AddTimer,
645     &MurphyMainloop::DelTimer,
646     &MurphyMainloop::ModTimer,
647     &MurphyMainloop::AddDefer,
648     &MurphyMainloop::DelDefer,
649     &MurphyMainloop::ModDefer,
650     &MurphyMainloop::Unregister,
651     NULL,
652     &MurphyMainloop::PollIo,
653   };
654
655   if (mrp_set_superloop(mainloop_, &ops, this)) {
656     poll_events_ = ops.poll_events;
657     return true;
658   } else {
659     mrp_log_error("Failed to set up superloop.");
660     return false;
661   }
662 }
663
664 // Murphy crosswalk logging backend
665 void MurphyMainloop::setupLogger(const char* logcfg, const char* dbgcfg) {
666   static bool registered = false;
667   const char *dbg, *log, *p, *n;
668   char        site[1024];
669   size_t      l;
670
671   if (registered)
672     return;
673
674   if (mrp_log_register_target("xwalk", xwalklogger, NULL))
675     mrp_log_set_target("xwalk");
676
677   // configure logging, environment variable overrides argument
678   if ((log = getenv(ENVVAR_LOG)) == NULL)
679     log = "none";
680
681   mrp_log_enable(mrp_log_parse_levels(log));
682
683   // configure debugging, environment variable overrides argument
684   if ((dbg = getenv(ENVVAR_DBG)) == NULL)
685     dbg = dbgcfg ? dbgcfg : "off";
686
687   if (strcmp(dbg, "off")) {
688     mrp_log_info("Enabling Murphy debugging (%s).", dbg);
689     mrp_debug_enable(true);
690
691     p = dbg;
692     while (p != NULL) {
693       n = strchr(p, ',');
694       l = n ? n - p : strlen(p);
695
696       if (l < sizeof(site) - 1) {
697         strncpy(site, p, l);
698         site[l] = '\0';
699         mrp_log_info("Enabling Murphy debug site '%s'.", site);
700         mrp_debug_set_config(site);
701       }
702       p = n ? n + 1 : NULL;
703     }
704   }
705   registered = true;
706 }
707
708 }  // namespace tizen