1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
|
// Copyright (c) 2012 The Native Client Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
/// @file
/// This example demonstrates building a dynamic library which is loaded by the
/// NaCl module. To load the NaCl module, the browser first looks for the
/// CreateModule() factory method (at the end of this file). It calls
/// CreateModule() once to load the module code from your .nexe. After the
/// .nexe code is loaded, CreateModule() is not called again.
///
/// Once the .nexe code is loaded, the browser then calls the CreateInstance()
/// method on the object returned by CreateModule(). If the CreateInstance
/// returns successfully, then Init function is called, which will load the
/// shared object on a worker thread. We use a worker because dlopen is
/// a blocking call, which is not alowed on the main thread.
#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
#include <ppapi/cpp/module.h>
#include <ppapi/cpp/completion_callback.h>
#include <ppapi/cpp/var.h>
#include <ppapi/cpp/instance.h>
#include "eightball.h"
/// The Instance class. One of these exists for each instance of your NaCl
/// module on the web page. The browser will ask the Module object to create
/// a new Instance for each occurrence of the <embed> tag that has these
/// attributes:
/// <pre>
/// type="application/x-nacl"
/// nacl="dlopen.nmf"
/// </pre>
class dlOpenInstance : public pp::Instance {
public:
explicit dlOpenInstance(pp::Core *core, PP_Instance instance):
pp::Instance(instance) {
_dlhandle = NULL;
_eightball = NULL;
_core = core;
_tid = 0;
};
virtual ~dlOpenInstance(){};
// Helper function to post a message back to the JS and stdout functions.
void logmsg(const char* pStr){
PostMessage(pp::Var(pStr));
fprintf(stdout, pStr);
}
// Initialize the module, staring a worker thread to load the shared object.
virtual bool Init(uint32_t argc, const char* argn[], const char* argv[]){
logmsg("Spawning thread to cache .so files...");
if (pthread_create(&_tid, NULL, LoadLibrariesOnWorker, this)) {
logmsg("ERROR; pthread_create() failed.\n");
return false;
}
return true;
}
// This function is called on a worker thread, and will call dlopen to load
// the shared object. In addition, note that this function does NOT call
// dlclose, which would close the shared object and unload it from memory.
void LoadLibrary()
{
const int32_t IMMEDIATELY = 0;
_dlhandle = dlopen("libeightball.so", RTLD_LAZY);
pp::CompletionCallback cc(LoadDoneCB, this);
_core->CallOnMainThread(IMMEDIATELY, cc , 0);
}
// This function will run on the main thread and use the handle it stored by
// the worker thread, assuming it successfully loaded, to get a pointer to the
// message function in the shared object.
void UseLibrary() {
_dlhandle = dlopen("libeightball.so", RTLD_LAZY);
if(_dlhandle == NULL) {
logmsg("libeightball.so did not load");
} else {
intptr_t offset = (intptr_t) dlsym(this->_dlhandle, "Magic8Ball");
_eightball = (TYPE_eightball) offset;
if (NULL == _eightball) {
std::string ballmessage = "dlsym() returned NULL: ";
ballmessage += dlerror();
ballmessage += "\n";
logmsg(ballmessage.c_str());
}
else{
logmsg("Eightball loaded!");
}
}
}
// Called by the browser to handle the postMessage() call in Javascript.
virtual void HandleMessage(const pp::Var& var_message) {
if(NULL == _eightball){
logmsg("Eightball library not loaded");
return;
}
if (!var_message.is_string()) {
logmsg("Message is not a string.");
return;
}
std::string message = var_message.AsString();
if (message == "query") {
fprintf(stdout, "%s(%d) Got this far.\n", __FILE__, __LINE__);
std::string ballmessage = "!The Magic 8-Ball says: ";
ballmessage += this->_eightball();
logmsg(ballmessage.c_str());
fprintf(stdout, "%s(%d) Got this far.\n", __FILE__, __LINE__);
} else {
std::string errormsg = "Unexpected message: ";
errormsg += message + "\n";
logmsg(errormsg.c_str());
}
}
static void* LoadLibrariesOnWorker(void *pInst) {
dlOpenInstance *inst = static_cast<dlOpenInstance *>(pInst);
inst->LoadLibrary();
return NULL;
}
static void LoadDoneCB(void *pInst, int32_t result) {
dlOpenInstance *inst = static_cast<dlOpenInstance *>(pInst);
inst->UseLibrary();
}
private:
void *_dlhandle;
TYPE_eightball _eightball;
pp::Core *_core;
pthread_t _tid;
};
// The Module class. The browser calls the CreateInstance() method to create
// an instance of your NaCl module on the web page. The browser creates a new
// instance for each <embed> tag with type="application/x-nacl".
class dlOpenModule : public pp::Module {
public:
dlOpenModule() : pp::Module() {}
virtual ~dlOpenModule() {}
// Create and return a dlOpenInstance object.
virtual pp::Instance* CreateInstance(PP_Instance instance) {
return new dlOpenInstance(core(), instance);
}
};
// Factory function called by the browser when the module is first loaded.
// The browser keeps a singleton of this module. It calls the
// CreateInstance() method on the object you return to make instances. There
// is one instance per <embed> tag on the page. This is the main binding
// point for your NaCl module with the browser.
namespace pp {
Module* CreateModule() {
return new dlOpenModule();
}
} // namespace pp
|