LCOV - code coverage report
Current view: directory - src/trusted/sel_universal - pepper_emu_handler.cc (source / functions) Found Hit Coverage
Test: coverage.lcov Lines: 112 4 3.6 %
Date: 2012-02-16 Functions: 0 0 -

       1                 : /*
       2                 :  * Copyright (c) 2011 The Native Client Authors. All rights reserved.
       3                 :  * Use of this source code is governed by a BSD-style license that can be
       4                 :  * found in the LICENSE file.
       5                 :  */
       6                 : 
       7                 : // This file exports a single function used to setup the
       8                 : // multimedia sub-system for use with sel_universal
       9                 : // It was inpspired by src/trusted/plugin/srpc/multimedia_socket.cc
      10                 : // On the untrusted side it interface with: src/untrusted/av/nacl_av.c
      11                 : //
      12                 : // NOTE: this is experimentation and testing. We are not concerned
      13                 : //       about descriptor and memory leaks
      14                 : 
      15                 : #include <string.h>
      16                 : #include <fstream>
      17                 : #include <queue>
      18                 : #include <string>
      19                 : 
      20                 : #include "ppapi/c/pp_errors.h"
      21                 : #include "ppapi/c/pp_input_event.h"
      22                 : #include "ppapi/c/pp_size.h"
      23                 : 
      24                 : #include "native_client/src/shared/platform/nacl_check.h"
      25                 : #include "native_client/src/shared/platform/nacl_log.h"
      26                 : #include "native_client/src/shared/platform/nacl_time.h"
      27                 : #include "native_client/src/shared/srpc/nacl_srpc.h"
      28                 : 
      29                 : 
      30                 : #include "native_client/src/trusted/sel_universal/rpc_universal.h"
      31                 : #include "native_client/src/trusted/sel_universal/primitives.h"
      32                 : #include "native_client/src/trusted/sel_universal/parsing.h"
      33                 : #include "native_client/src/trusted/sel_universal/pepper_emu.h"
      34                 : 
      35                 : // ======================================================================
      36                 : const int kInvalidInstance = 0;
      37                 : const int kInvalidHandle = 0;
      38                 : // We currently have no bookkeeping for events, so this resource handle is
      39                 : // used for all of them.
      40                 : const int kFirstEventHandle = 6000;
      41                 : 
      42                 : // ======================================================================
      43                 : 
      44                 : // Note: Just a bunch of fairly unrelated global variables,
      45                 : // we expect them to be zero initialized.
      46              22 : static struct {
      47                 :   int instance;
      48                 : 
      49                 :   // for event loggging and replay
      50                 :   std::ofstream event_logger_stream;
      51                 :   std::ifstream event_replay_stream;
      52                 :   std::queue<UserEvent*> events_ready_to_go;
      53                 :   UserEvent* next_sync_event;
      54                 : 
      55                 :   IMultimedia* sdl_engine;
      56                 :   std::string title;
      57                 : 
      58                 :   std::string quit_message;
      59              22 : } Global;
      60                 : 
      61                 : // ======================================================================
      62                 : bool HandlerPepperEmuInitialize(NaClCommandLoop* ncl,
      63               0 :                                 const vector<string>& args) {
      64               0 :   NaClLog(LOG_INFO, "HandlerSDLInitialize\n");
      65               0 :   if (args.size() < 5) {
      66               0 :     NaClLog(LOG_ERROR, "Insufficient arguments to 'rpc' command.\n");
      67               0 :     return false;
      68                 :   }
      69                 : 
      70                 :   UNREFERENCED_PARAMETER(ncl);
      71               0 :   Global.instance = ExtractInt32(args[1]);
      72               0 :   Global.title = args[4];
      73                 : 
      74                 :   // NOTE: we decide at linktime which incarnation to use here
      75                 :   Global.sdl_engine = MakeEmuPrimitives(ExtractInt32(args[2]),
      76                 :                                         ExtractInt32(args[3]),
      77               0 :                                         Global.title.c_str());
      78               0 :   PepperEmuInitAudio(ncl, Global.sdl_engine);
      79               0 :   PepperEmuInitCore(ncl, Global.sdl_engine);
      80               0 :   PepperEmuInitFileIO(ncl, Global.sdl_engine);
      81               0 :   PepperEmuInitPostMessage(ncl, Global.sdl_engine);
      82               0 :   PepperEmuInit3D(ncl, Global.sdl_engine);
      83               0 :   PepperEmuInit2D(ncl, Global.sdl_engine);
      84               0 :   return true;
      85                 : }
      86                 : 
      87                 : 
      88               0 : static UserEvent* GetNextEvent(bool poll) {
      89               0 :   UserEvent* event = NULL;
      90               0 :   if (Global.event_replay_stream.is_open()) {
      91               0 :     if (Global.events_ready_to_go.size() > 0) {
      92                 :       // empty queue while we have ready to events
      93               0 :       event = Global.events_ready_to_go.front();
      94               0 :       Global.events_ready_to_go.pop();
      95               0 :       return event;
      96               0 :     } else if (Global.next_sync_event != NULL) {
      97                 :       // wait for the matching sync event
      98               0 :       event = Global.sdl_engine->EventGet();
      99                 : 
     100               0 :       if (IsTerminationEvent(event)) return event;
     101                 : 
     102                 :       // drop all regular events on the floor;
     103               0 :       if (IsInputEvent(event)) return NULL;
     104                 : 
     105                 :       // NOTE: we only replay the recorded input events.
     106                 :       // Recorded UserEvents are used for synchronization with the
     107                 :       // actual UserEvents that the system generates.
     108                 :       // TODO(robertm): We may need to refine this because, in theory,
     109                 :       // there is no guaranteed time ordering on the UserEvents.
     110                 :       // One solution would be to only use the screen refresh
     111                 :       // UserEvents (CUSTOM_EVENT_FLUSH_CALLBACK) as sync events and
     112                 :       // ignore all others.
     113                 :       // We can delay this work until we see the check below firing.
     114               0 :       CHECK(event->type == Global.next_sync_event->type);
     115                 :       // sync event has been "consumed"
     116               0 :       Global.next_sync_event = NULL;
     117               0 :       return event;
     118                 :     } else {
     119                 :       // refill queue
     120               0 :       if (Global.event_replay_stream.eof()) {
     121               0 :         NaClLog(LOG_INFO, "replay events depleted\n");
     122               0 :         Global.events_ready_to_go.push(MakeTerminationEvent());
     123               0 :         return NULL;
     124                 :       }
     125               0 :       while (true) {
     126               0 :         event = new UserEvent;
     127                 :         Global.event_replay_stream.read(
     128               0 :           reinterpret_cast<char*>(event), sizeof(*event));
     129               0 :         if (Global.event_replay_stream.fail()) return NULL;
     130               0 :         CHECK(!IsInvalidEvent(event));
     131               0 :         if (!IsInputEvent(event)) {
     132               0 :           Global.next_sync_event = event;
     133               0 :           return NULL;
     134                 :         } else {
     135               0 :           Global.events_ready_to_go.push(event);
     136                 :         }
     137                 :       }
     138                 :     }
     139                 :   } else {
     140               0 :     if (poll) {
     141               0 :       return Global.sdl_engine->EventPoll();
     142                 :     } else {
     143               0 :       return Global.sdl_engine->EventGet();
     144                 :     }
     145                 :   }
     146                 : }
     147                 : 
     148                 : 
     149                 : static void InvokeCompletionCallback(NaClCommandLoop* ncl,
     150                 :                                      int callback,
     151                 :                                      int result,
     152                 :                                      void* data,
     153               0 :                                      int size) {
     154                 :   NaClSrpcArg  in[NACL_SRPC_MAX_ARGS];
     155                 :   NaClSrpcArg* ins[NACL_SRPC_MAX_ARGS + 1];
     156                 :   NaClSrpcArg  out[NACL_SRPC_MAX_ARGS];
     157                 :   NaClSrpcArg* outs[NACL_SRPC_MAX_ARGS + 1];
     158               0 :   BuildArgVec(outs, out, 0);
     159               0 :   BuildArgVec(ins, in, 3);
     160                 : 
     161               0 :   int dummy_exception[2] = {0, 0};
     162                 : 
     163               0 :   ins[0]->tag = NACL_SRPC_ARG_TYPE_INT;
     164               0 :   ins[0]->u.ival = callback;
     165               0 :   ins[1]->tag = NACL_SRPC_ARG_TYPE_INT;
     166               0 :   ins[1]->u.ival = result;
     167               0 :   ins[2]->tag = NACL_SRPC_ARG_TYPE_CHAR_ARRAY;
     168               0 :   if (data) {
     169               0 :     ins[2]->u.count = size;;
     170               0 :     ins[2]->arrays.carr = reinterpret_cast<char*>(data);
     171                 :   } else {
     172               0 :     ins[2]->u.count = sizeof(dummy_exception);
     173               0 :     ins[2]->arrays.carr = reinterpret_cast<char*>(dummy_exception);
     174                 :   }
     175                 : 
     176               0 :   ncl->InvokeNexeRpc("RunCompletionCallback:iiC:", ins, outs);
     177               0 : }
     178                 : 
     179                 : 
     180               0 : static bool HandleSynthesizedEvent(NaClCommandLoop* ncl, UserEvent* event) {
     181                 :   NaClLog(1, "Got sythesized event [%s]\n",
     182               0 :           StringifyEvent(event).c_str());
     183                 : 
     184               0 :   switch (event->type) {
     185                 :     case EVENT_TYPE_TERMINATION:
     186               0 :       NaClLog(LOG_INFO, "Got termination event\n");
     187               0 :       return false;
     188                 : 
     189                 :     // This event is created on behalf of PPB_URLLoader_Open
     190                 :     case EVENT_TYPE_OPEN_CALLBACK:
     191                 :     // FALL THROUGH
     192                 :     // This event is created on behalf of PPB_Core_CallOnMainThread
     193                 :     case EVENT_TYPE_TIMER_CALLBACK:
     194                 :     // FALL THROUGH
     195                 :     // This event is created on behalf of PPB_URLLoader_ReadResponseBody
     196                 :     case EVENT_TYPE_READ_CALLBACK:
     197                 :     // FALL THROUGH
     198                 :     // This event gets created so that we can invoke
     199                 :     // RunCompletionCallback after PPB_Graphics2D_Flush
     200                 :     case EVENT_TYPE_FLUSH_CALLBACK: {
     201                 :       InvokeCompletionCallback(ncl,
     202                 :                                event->callback,
     203                 :                                event->result,
     204                 :                                event->pointer,
     205               0 :                                event->size);
     206               0 :       return true;
     207                 :     }
     208                 :     // This event gets created so that we can invoke
     209                 :     // PPP_Audio_StreamCreated after PPB_Audio_Create
     210                 :     case EVENT_TYPE_INIT_AUDIO:
     211                 : #if (NACL_LINUX || NACL_OSX)
     212               0 :       sleep(1);
     213                 : #elif NACL_WINDOWS
     214                 :       Sleep(1 * 1000);
     215                 : #else
     216                 : #error "Please specify platform as NACL_LINUX, NACL_OSX or NACL_WINDOWS"
     217                 : #endif
     218               0 :       InvokeAudioStreamCreatedCallback(ncl, event);
     219               0 :       return true;
     220                 :     case EVENT_TYPE_INPUT:
     221                 :     case EVENT_TYPE_INVALID:
     222                 :     default:
     223               0 :       NaClLog(LOG_FATAL, "unknown event type %d\n", event->type);
     224               0 :       return false;
     225                 :   }
     226                 : }
     227                 : 
     228                 : // The event loop below see two kinds of events. Regular input events
     229                 : // such as keyboard and mouse events. And synthetic events that got injected
     230                 : // into the event queue to trigger callbacks.
     231                 : // The input events are forwarded to the nexe.
     232                 : // The synthetic events are converted to the corresponding callback invokation.
     233                 : //
     234                 : // Having callbacks and input events going through the same queue has some
     235                 : // advantages. In particular we can use the non-input events
     236                 : // as synchronization markers (e.g. sync on every screen update) in the replay
     237                 : // case.
     238                 : bool HandlerPepperEmuEventLoop(NaClCommandLoop* ncl,
     239               0 :                                const vector<string>& args) {
     240               0 :   NaClLog(LOG_INFO, "HandlerPepperEmuEventLoop\n");
     241                 :   UNREFERENCED_PARAMETER(ncl);
     242               0 :   if (args.size() < 3) {
     243               0 :     NaClLog(LOG_ERROR, "Insufficient arguments to 'rpc' command.\n");
     244               0 :     return false;
     245                 :   }
     246                 : 
     247               0 :   const bool poll = ExtractInt32(args[1]) != 0;
     248               0 :   const int msecs = ExtractInt32(args[2]);
     249                 : 
     250                 :   NaClLog(LOG_INFO, "Entering event loop. Polling: %d  duration_ms: %d\n",
     251               0 :           poll, msecs);
     252                 : 
     253               0 :   int64_t termination_time = NaClGetTimeOfDayMicroseconds() + msecs * 1000;
     254               0 :   bool keep_going = true;
     255               0 :   while (keep_going && NaClGetTimeOfDayMicroseconds() < termination_time) {
     256               0 :     NaClLog(2, "Pepper emu event loop wait\n");
     257               0 :     UserEvent* event = GetNextEvent(poll);
     258               0 :     if (event == NULL) {
     259               0 :       continue;
     260                 :     }
     261                 : 
     262               0 :     if (Global.event_logger_stream.is_open() && !IsInvalidEvent(event)) {
     263                 :       Global.event_logger_stream.write(reinterpret_cast<char*>(event),
     264               0 :                                        sizeof(*event));
     265                 :     }
     266                 : 
     267               0 :     if (IsInputEvent(event)) {
     268                 :       // NOTE: for now always use the same event resource
     269               0 :       InvokeInputEventCallback(ncl, event, Global.instance, kFirstEventHandle);
     270                 :     } else {
     271               0 :       keep_going = HandleSynthesizedEvent(ncl, event);
     272                 :     }
     273                 :     // NOTE: this is the global event sink where all events get deleted.
     274               0 :     delete event;
     275                 :   }
     276                 : 
     277                 :   NaClLog(LOG_INFO, "Exiting event loop (%s)\n",
     278               0 :           keep_going ? "timeout" : "termination");
     279               0 :   return true;
     280                 : }
     281                 : 
     282                 : 
     283               0 : void RecordPPAPIEvents(std::string filename) {
     284               0 :   NaClLog(LOG_INFO, "recoding events to %s\n", filename.c_str());
     285                 :   Global.event_logger_stream.open(
     286               0 :     filename.c_str(), std::ios::out | std::ios::trunc | std::ios::binary);
     287               0 :   if (!Global.event_logger_stream.is_open()) {
     288               0 :     NaClLog(LOG_FATAL, "Cannot open %s\n", filename.c_str());
     289                 :   }
     290               0 : }
     291                 : 
     292                 : 
     293               0 : void ReplayPPAPIEvents(std::string filename) {
     294               0 :   NaClLog(LOG_INFO, "replaying events from %s\n", filename.c_str());
     295               0 :   Global.next_sync_event = NULL;
     296                 :   Global.event_replay_stream.open(filename.c_str(),
     297               0 :                                   std::ios::in | std::ios::binary);
     298               0 :   if (!Global.event_replay_stream.is_open()) {
     299               0 :     NaClLog(LOG_FATAL, "Cannot open %s\n", filename.c_str());
     300                 :   }
     301              22 : }

Generated by: LCOV version 1.7