lua-users home
lua-l archive

[Date Prev][Date Next][Thread Prev][Thread Next] [Date Index] [Thread Index]


It was thus said that the Great Coroutines once stated:
> On Fri, Aug 22, 2014 at 11:33 PM, Sean Conner <sean@conman.org> wrote:
> 
> >   Okay, now I'm totally confused as to what you are trying to do.  Let's
> > take, for example, LPeg.
> >
> >         > lpeg = require "lpeg" -- I'm using 0.12 BTW
> >         > x = lpeg.P "Coroutines"
> >         > print(type(x))
> >         userdata: 0x8835e7c
> 
> >   Okay, what exactly, are you trying to modify?
> 
> Okay.  From Lua you have a userdata object.  

	f = io.open("Mail/lua-list","r")

  Okay, I have my userdata.

> You can use # to get the
> size of that, assuming __len isn't doing anything deceptive.  

  Um.  So what should #f return in this case?  The size of the file?  Works
fine for real files, but how about

	f = io.open("/dev/zero","r")

What does

	x = lpeg.P "Coroutines"
	print(#x)

even mean?

> I want to be able to string.sub() userdata, so I can read
> character-by-character.  Promoting a lua_Buffer/userdata to a string
> hashes the userdata and from then on it's known as a string to Lua, and I
> cannot modify it.

  Okay, you are definitely associating "userdata" with "large, growable
character array".  userdata is more than just that.

> >   I also don't fully understand what you mean by:
> >
> >> I dream of a world without data channels and serializing things
> 
> The cost of serializing an object and sharing it through some method
> of IPC is more than it needs to be.  I take issue with the concept of
> it.  When I have brought this up before I'm told to look elsewhere for
> inefficiency, but I am someone who likes to solve benign problems.
> Also lock-free algorithms are a thing.  Message-passing will never be
> as quick as zero-copied, shared data ;>

  The Amiga did zero-copy message passing.  Upside:  it was quick. 
Downsides:

	1) if the sending thread/process crashed, you leaked memory
	
	2) you could only send messages to other threads/processes on the
	   same system.

	3) you could crash the system if you did it wrong.

  By 3, I mean doing something like:

	struct mymessage
	{
	  struct Message msg;
	  int            important;
	}
	
	int blowitup(void)
	{
	  struct MsgPort   *port;
	  struct mymessage  mess;	
	  
	  mess.msg.mn_Length    = sizeof(mess);
	  mess.msg.mn_ReplyPort = NULL;
	  mess.important        = 1;
	  
	  port = FindPort("somemessageport");
	  if (port) 
	    PutMsg(port,&mess);
	}
	
	/* um ... we just blew up the system */
	
  Even if you were careful and allocated the message, you could still cause
havoc:

	struct mymessage
	{
	  struct Message  msg;
	  char           *important;
	}
	
	int blowitup(void)
	{
	  struct MsgPort   *port;
	  struct mymessage *mess;
	  char             *important;
	  
	  mess = malloc(sizeof(mess));
	  important = malloc(32);
	  if ((mess == NULL) || (important == NULL))
	  {
 	    free(mess);
 	    free(important);
 	    return -1;
 	  }
 	  
 	  strcpy(important,"Boom!");
 	  mess->msg.mn_Length = sizeof(mess);
 	  mess->msg.mn_ReplyPort = NULL;
 	  mess->important = important;
 	  
 	  port = FindPort("somemessageport");
 	  if (port)
 	    PutMsg(port,mess);
 	  /* Boom! */
 	  free(important);
 	}

  The Amiga could do this because it didn't have virtual memory (even though
it was a multitasking operating system---the two are othogonal and having
one doesn't imply the other) and thus, it worked.

  But once you introduce virtual memory, then you have three options:
  
	1) Shared memory.  It gets somewhat problematic if process A wants
	to send a message to B, who then wants to send it to C.  It's not
	really an "ad-hoc, let's just do it" type of operation; all the
	processes must co-ordinate first, leading to large up-front costs.
	
	And you still have the problem with my second example.  
	
	2) Play tricks with virtual memory tables.  Messages now become a
	minimum of a page size (unless you really like leaking possibly
	sensitive information) and must be allocated specially (but that can
	be hidden behind a function).  Issues to work out: when the message
	is passed, is it mapped out of A?  Do A and B now have a copy?

	But you still have the problem with my second example.
	
	3) Copy the message.  QNX does this (it's a message-based
	microkernel).  Don't discount it---back in the 90s, I knew the
	owners of a software company that wrote commerical X Window servers,
	and their fastest X server was on QNX, message passing and all.

	You still have an issue with copying a pointer value across, so you
	still have the problem of my second example.

  And all that which leads me to my point---you *still* have serialization
issues, even if you have zero-copy message passing.  You can't get away from
it.  And on the down side, you are limiting your messaging to a single box. 
Getting back to QNX---because it was pure message-passing, you could run a
command on box A, reference a file on box B, pipe the output to a command on
box C and write the output to box D, all from box E.  At the command line. 
That looked a lot like any other command you would type.  On a Unix system.

  All because of message passing (and proper serialization).
  
  -spc