Index: native_client_sdk/src/libraries/nacl_io/devfs/jspipe_node.cc |
diff --git a/native_client_sdk/src/libraries/nacl_io/devfs/jspipe_node.cc b/native_client_sdk/src/libraries/nacl_io/devfs/jspipe_node.cc |
index 7979e33a29d8cc09a19b3e459e3664ba84c35386..8b670d74f36aae6c0e5ad2cb5d89c7432ba5a8c8 100644 |
--- a/native_client_sdk/src/libraries/nacl_io/devfs/jspipe_node.cc |
+++ b/native_client_sdk/src/libraries/nacl_io/devfs/jspipe_node.cc |
@@ -4,94 +4,186 @@ |
#include "nacl_io/devfs/jspipe_node.h" |
-//#include <cstdio> |
#include <cstring> |
#include "nacl_io/devfs/dev_fs.h" |
#include "nacl_io/error.h" |
#include "nacl_io/ioctl.h" |
#include "nacl_io/kernel_handle.h" |
+#include "nacl_io/log.h" |
#include "nacl_io/pepper_interface.h" |
+#define TRACE(format, ...) LOG_TRACE("jspipe: " format, ##__VA_ARGS__) |
+#define ERROR(format, ...) LOG_TRACE("jspipe: " format, ##__VA_ARGS__) |
+ |
+namespace { |
+const size_t kPostMessageBufferSize = 512*1024; |
+} |
+ |
namespace nacl_io { |
-#define MAX_MESSAGE_SIZE (64*1024) |
-Error JSPipeNode::Write(const HandleAttr& attr, |
- const void* buf, |
- size_t count, |
- int* out_bytes) { |
+JSPipeNode::JSPipeNode(Filesystem* filesystem) |
+ : Node(filesystem), |
+ pipe_(new JSPipeEventEmitter(filesystem_->ppapi(), kPostMessageBufferSize)), |
+ messaging_iface_(NULL), |
+ var_iface_(NULL), |
+ array_iface_(NULL), |
+ buffer_iface_(NULL), |
+ dict_iface_(NULL) { |
PepperInterface* ppapi = filesystem_->ppapi(); |
- MessagingInterface* iface = ppapi->GetMessagingInterface(); |
- VarInterface* var_iface = ppapi->GetVarInterface(); |
- VarArrayInterface* array_iface = ppapi->GetVarArrayInterface(); |
- VarArrayBufferInterface* buffer_iface = ppapi->GetVarArrayBufferInterface(); |
- if (!iface || !var_iface || !array_iface || !buffer_iface) |
- return ENOSYS; |
+ if (ppapi) { |
+ messaging_iface_ = ppapi->GetMessagingInterface(); |
+ var_iface_ = ppapi->GetVarInterface(); |
+ array_iface_ = ppapi->GetVarArrayInterface(); |
+ buffer_iface_ = ppapi->GetVarArrayBufferInterface(); |
+ dict_iface_ = ppapi->GetVarDictionaryInterface(); |
+ } else { |
+ TRACE("missing PPAPI provider"); |
+ } |
+} |
- if (name_.empty()) |
+JSPipeEventEmitter* JSPipeNode::GetEventEmitter() { |
+ return pipe_.get(); |
+} |
+ |
+Error JSPipeNode::HandleJSWrite(struct PP_Var message) { |
+ TRACE("HandleJSWrite"); |
+ if (message.type != PP_VARTYPE_ARRAY_BUFFER) { |
+ TRACE("HandleJSWrite expected ArrayBuffer but got %d.", message.type); |
+ return EINVAL; |
+ } |
+ uint32_t length; |
+ if (buffer_iface_->ByteLength(message, &length) != PP_TRUE) |
+ return EINVAL; |
+ |
+ char* buffer = (char*)buffer_iface_->Map(message); |
+ |
+ // Write data to the input fifo |
+ int wrote = GetEventEmitter()->HandleJSWrite(buffer, length); |
binji
2014/05/01 20:22:31
returns size_t
|
+ buffer_iface_->Unmap(message); |
+ if (wrote != (int) length) { |
+ LOG_ERROR("Only wrote %d of %d bytes to pipe", wrote, length); |
binji
2014/05/01 20:22:31
ERROR instead of LOG_ERROR?
Sam Clegg
2014/05/01 22:16:55
File local macro that also print the name of the p
|
return EIO; |
+ } |
+ TRACE("done HandleWrite: %d", length); |
+ return 0; |
+} |
- // Limit the size of the data we send with PostMessage to MAX_MESSAGE_SIZE |
- if (count > MAX_MESSAGE_SIZE) |
- count = MAX_MESSAGE_SIZE; |
+Error JSPipeNode::HandleJSAck(PP_Var message) { |
+ if (message.type != PP_VARTYPE_INT32) { |
+ TRACE("HandleAck integer object expected but got %d.", message.type); |
+ return EINVAL; |
+ } |
+ GetEventEmitter()->HandleJSAck(message.value.as_int); |
binji
2014/05/01 20:22:31
This will never be able to ack above 2**31
Sam Clegg
2014/05/01 22:16:55
True, this is a current know issue that also effec
|
+ return 0; |
+} |
- // Copy data in a new ArrayBuffer |
- PP_Var buffer = buffer_iface->Create(count); |
- memcpy(buffer_iface->Map(buffer), buf, count); |
- buffer_iface->Unmap(buffer); |
+Error JSPipeNode::HandleJSMessage(struct PP_Var message) { |
+ Error err = 0; |
+ if (!messaging_iface_ || !var_iface_ || !array_iface_ || !buffer_iface_) { |
+ TRACE("HandleJSMessage: missing PPAPI interfaces"); |
+ return ENOSYS; |
+ } |
+ |
+ // Verify that we have an array with size two. |
+ if (message.type != PP_VARTYPE_ARRAY) { |
+ TRACE("HandleJSMessage passed non-array var"); |
+ return EINVAL; |
+ } |
+ |
+ if (array_iface_->GetLength(message) != 2) { |
+ TRACE("HandleJSMessage passed array of size %d", |
+ array_iface_->GetLength(message)); |
+ return EINVAL; |
+ } |
- // Construct string var containing the name of the pipe |
- PP_Var string = var_iface->VarFromUtf8(name_.c_str(), name_.size()); |
+ PP_Var message_type_var = array_iface_->Get(message, 0); |
+ PP_Var payload = array_iface_->Get(message, 1); |
+ if (message_type_var.type != PP_VARTYPE_STRING) { |
+ err = EINVAL; |
+ } else { |
+ uint32_t length; |
+ const char* message_type_string; |
+ message_type_string = var_iface_->VarToUtf8(message_type_var, &length); |
+ std::string message_type(message_type_string, length); |
+ |
+ TRACE("HandleJSMessage %s", message_type.c_str()); |
+ if (message_type == "write") { |
+ err = HandleJSWrite(payload); |
+ } else if (message_type == "ack") { |
+ err = HandleJSAck(payload); |
+ } else { |
+ TRACE("Unknown message type: %s", message_type.c_str()); |
+ err = EINVAL; |
+ } |
+ } |
- // Construct two element array containing string and array buffer |
- PP_Var array = array_iface->Create(); |
- array_iface->Set(array, 0, string); |
- array_iface->Set(array, 1, buffer); |
+ var_iface_->Release(message_type_var); |
+ var_iface_->Release(payload); |
+ return err; |
+} |
- // Release our handles to the items that are now in the array |
- var_iface->Release(string); |
- var_iface->Release(buffer); |
+Error JSPipeNode::Read(const HandleAttr& attr, |
+ void* buf, |
+ size_t count, |
+ int* out_bytes) { |
+ int ms = attr.IsBlocking() ? -1 : 0; |
- // Send array via PostMessage |
- iface->PostMessage(ppapi->GetInstance(), array); |
+ EventListenerLock wait(GetEventEmitter()); |
+ Error err = wait.WaitOnEvent(POLLIN, ms); |
+ if (err == ETIMEDOUT) |
+ err = EWOULDBLOCK; |
+ if (err) |
+ return err; |
- // Release the array |
- var_iface->Release(array); |
+ *out_bytes = GetEventEmitter()->Read_Locked(static_cast<char*>(buf), count); |
+ return 0; |
+} |
- *out_bytes = count; |
+Error JSPipeNode::Write(const HandleAttr& attr, |
+ const void* buf, |
+ size_t count, |
+ int* out_bytes) { |
+ int ms = attr.IsBlocking() ? -1 : 0; |
+ TRACE("write %d", ms); |
+ |
+ EventListenerLock wait(GetEventEmitter()); |
+ Error err = wait.WaitOnEvent(POLLOUT, ms); |
+ if (err == ETIMEDOUT) |
+ err = EWOULDBLOCK; |
+ if (err) |
+ return err; |
+ |
+ *out_bytes = GetEventEmitter()->Write_Locked(static_cast<const char*>(buf), |
+ count); |
return 0; |
} |
Error JSPipeNode::VIoctl(int request, va_list args) { |
- switch (request) { |
- case TIOCNACLPIPENAME: { |
- // name can only be set once |
- if (!name_.empty()) |
- return EIO; |
+ AUTO_LOCK(node_lock_); |
+ switch (request) { |
+ case NACL_IOC_PIPE_SETNAME: { |
const char* new_name = va_arg(args, char*); |
- // new name must not be empty |
- if (!new_name || strlen(new_name) == 0) |
- return EIO; |
- |
- name_ = new_name; |
+ return GetEventEmitter()->SetName(new_name); |
+ } |
+ case NACL_IOC_PIPE_GETISPACE: { |
+ int* space = va_arg(args, int*); |
+ *space = GetEventEmitter()->GetISpace(); |
return 0; |
} |
- case TIOCNACLINPUT: { |
- // This ioctl is used to deliver data from javascipt into the pipe. |
- struct tioc_nacl_input_string* message = |
- va_arg(args, struct tioc_nacl_input_string*); |
- const char* buffer = message->buffer; |
- int num_bytes = message->length; |
- int wrote = 0; |
- HandleAttr data; |
- // Write to the underlying pipe. Calling JSPipeNode::Write |
- // would write using PostMessage. |
- int error = PipeNode::Write(data, buffer, num_bytes, &wrote); |
- if (error || wrote != num_bytes) |
- return EIO; |
+ case NACL_IOC_PIPE_GETOSPACE: { |
+ int* space = va_arg(args, int*); |
+ *space = GetEventEmitter()->GetOSpace(); |
return 0; |
} |
+ case NACL_IOC_HANDLEMESSAGE: { |
+ struct PP_Var* message = va_arg(args, struct PP_Var*); |
+ return HandleJSMessage(*message); |
+ } |
+ default: |
+ TRACE("unknown ioctl: %#x", request); |
+ break; |
} |
return EINVAL; |