blob: d9f1eb82e66f4f40ddf3de1a062a2936c1c98b36 [file] [log] [blame]
/*
* Copyright (c) 2011 The Chromium Authors. All rights reserved.
* Use of this source code is governed by a BSD-style license that can be
* found in the LICENSE file.
*/
//
// Post-message based test for simple rpc based access to name services.
//
#include <string>
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <inttypes.h>
#include <sys/fcntl.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include "native_client/src/include/nacl_base.h"
#include "ppapi/cpp/instance.h"
#include "ppapi/cpp/module.h"
#include "ppapi/cpp/var.h"
class MyInstance : public pp::Instance {
public:
explicit MyInstance(PP_Instance instance);
virtual ~MyInstance();
virtual void HandleMessage(const pp::Var& message_data);
private:
DISALLOW_COPY_AND_ASSIGN(MyInstance);
};
// ---------------------------------------------------------------------------
MyInstance::MyInstance(PP_Instance instance)
: pp::Instance(instance) {
}
MyInstance::~MyInstance() {
}
typedef std::map<std::string, std::string> KeyValueMap;
static void ParseMapEntry(KeyValueMap* map,
std::string const& entry) {
std::string::size_type eq = entry.find('=');
std::string key;
std::string val = "";
if (std::string::npos != eq) {
key = entry.substr(0, eq);
val = entry.substr(eq+1);
} else {
key = entry;
}
(*map)[key] = val;
}
//
// parse a name1=value1,name2=value2 string into a map, using NRVO. spaces
// are significant (!).
//
static KeyValueMap ParseMap(std::string const& str_map) {
KeyValueMap nrvo;
std::string::size_type s = 0;
std::string::size_type comma;
while (std::string::npos != (comma = str_map.find(',', s))) {
std::string sub = str_map.substr(s, comma - s);
s = comma + 1;
ParseMapEntry(&nrvo, sub);
}
if (s != str_map.size()) {
std::string sub = str_map.substr(s);
ParseMapEntry(&nrvo, sub);
}
return nrvo;
}
static std::string quotes[] = {
"In the year 1878 I took my degree of Doctor of Medicine...\n",
"A merry little surge of electricity piped by automatic alarm...\n",
"Squire Trelawney, Dr. Livesey, and the rest of these gentlemen...\n",
("It is a truth universally acknowledged,"
" that a single man in possession...\n"),
};
void output_quote(int desc, size_t ix) {
const char* out = quotes[ix].c_str();
size_t len = strlen(out);
(void) write(desc, out, len); /* assumes no partial writes! */
}
//
// thread start function -- output asynchronously.
//
/* calling conv */ extern "C" {
static void* bg_thread(void* state) {
KeyValueMap* kvm(reinterpret_cast<KeyValueMap*>(state));
std::string out = (*kvm)["stream"];
std::string sleep_str;
int sleep_us = 0;
if ((*kvm).find("delay_us") != (*kvm).end()) {
sleep_str = (*kvm)["delay_us"];
if (sleep_str.length() > 0) {
sleep_us = strtoul(sleep_str.c_str(), 0, 0);
}
}
// Try to check that output works when the event handler thread has
// already returned back to JavaScript, as opposed to output
// occuring while the plugin is still executing the event handler
// and blocking the JavaScript main thread.
if (sleep_us > 0) {
usleep(sleep_us);
}
if (out == "stdout") {
output_quote(1, 2);
} else if (out == "stderr") {
output_quote(2, 3);
} else {
fprintf(stderr, "bg_thread: unrecognized output stream %s\n",
out.c_str());
}
return NULL;
}
} // extern "C"
// HandleMessage gets invoked when postMessage is called on the DOM
// element associated with this plugin instance. In this case, if we
// are given a string, we'll post a message back to JavaScript with a
// reply -- essentially treating this as a string-based RPC.
void MyInstance::HandleMessage(const pp::Var& message) {
std::string msg = "None";
if (message.is_string()) {
msg = message.AsString();
KeyValueMap test_arg(ParseMap(msg));
if (test_arg["thread"] == "fg") {
std::string out = test_arg["stream"];
if (out == "stdout") {
output_quote(1, 0);
} else if (out == "stderr") {
output_quote(2, 1);
} else {
fprintf(stderr, "HandleMessage: unrecognized output stream %s\n",
out.c_str());
}
} else {
/* spawn thread to do output */
pthread_t tid;
pthread_create(&tid,
reinterpret_cast<const pthread_attr_t *>(NULL),
bg_thread,
reinterpret_cast<void *>(new KeyValueMap(test_arg)));
pthread_detach(tid);
}
} else {
fprintf(stderr, "HandleMessage: message is not a string\n");
fflush(NULL);
}
}
// This object is the global object representing this plugin library as long
// as it is loaded.
class MyModule : public pp::Module {
public:
MyModule() : pp::Module() {}
virtual ~MyModule() {}
// Override CreateInstance to create your customized Instance object.
virtual pp::Instance *CreateInstance(PP_Instance instance);
DISALLOW_COPY_AND_ASSIGN(MyModule);
};
pp::Instance *MyModule::CreateInstance(PP_Instance pp_instance) {
return new MyInstance(pp_instance);
}
namespace pp {
// Factory function for your specialization of the Module object.
Module* CreateModule() {
return new MyModule();
}
} // namespace pp