True. Here are some ideas:AndrewAPrice wrote:There are a lot of implementation details we'd need to figure out if we want to do function calls between processes.
I don't see why not. If process B has a pointer to the object, it must be because process A explicitly gave it one. Shared memory is an essential form of IPC.AndrewAPrice wrote:Can you share memory between processes? (Let's say I allocate a class in Process A, can Process B access it and call methods on it?)
I don't think it's very interesting to let processes own memory. Modern allocator designs based around thread-local caches are well-suited to such a design as this one. (Incidentall, memory management as a whole becomes simpler and faster in an SASOS. You still want to have a multi-level allocator—first pages, or superpages; then individual objects—to avoid false sharing problems, but the second level isn't slow. That means the allocator has less incentive to keep around extra pages, which means less overall memory usage.) Mimalloc's design works especially well here; it allows you to efficiently free objects originating in other threads. But even classic tcmalloc/jemalloc will work well.AndrewAPrice wrote:How do you determine what process owns a chunk of memory?
If ownership of objects can be moved, could a malicious program keep calling a critical service with a large payload?
Options:AndrewAPrice wrote:How do you handle terminating processes? (E.g. Imagine Process A calls Process B which calls Process C, but B terminates while C is still doing something. What will happen when C returns?)
- Make all messages async. Have a synchronous call to 'wait for any message to arrive along any channel', or one to 'wait for any message to arrive along this specific channel'. If a process dies, all its channels are destroyed. If you wait for a destroyed channel, you get a signal (or some other form of error).
- Same as (1) but don't destroy a process's channels when it dies. Instead, keep around the channels and let the process transparently resume and continue communicating along them. Prior art: erlang.
- Messages are synchronous (more like a classic function call). If a process encounters an error, that error is returned or signaled as it would be if the error happened in the same process
Like I said previously, all memory can be shared. Since the code implementing the interface still has references to it, it isn't freed when A terminates it, and B is free to continue calling it. (Or the code is copied (or COWed), depending on the semantics you want. Same story either way.)AndrewAPrice wrote:What happens if Process A implements an interface, sends the object to Process B, then A terminates, and B tries to call a virtual method on the interface?
Express APIs abstractly in on-disc binaries. The runtime is responsible for doing zero-copy (de)serialization, which gives you the same performance but lets you verify API calls at startup time.AndrewAPrice wrote:What happens if Process A is updated and the exported function's signature changes, but Process B is a commercial closed source application and the developers haven't rebuilt it for the newer API, and it tries to call Process A with the wrong function signature?