2

I've been reading Principles of Computer System Design (Saltzer & Kaashoek), and one of the early chapters is on modularity. For example:

  • Different modules should only interact through specified interfaces
  • Modules should be constructed to expose as little of their internal implementation as possible

Now that's all pretty standard stuff, and is the way most OO languages work. However, they mention even stricter requirements, such as:

  • A called module should not be able to lock up the caller by failing to return
  • A called module should not be able to cause its caller to die by running out of stack space

Now these requirements make perfect sense to me, and would do much to stop errors propagating through the entirety of a massive program and bring it all crashing down.

However, the method they suggest, splitting everything up into client/server processes, seems somewhat of an overkill for many purposes. Writing everything you want to modularize as client/server seems to be both:

  • incredibly tedious
  • slow (w.r.t. execution speed)

For example, I would like to be able to delegate work to my Math module, and place limits on execution time and memory use, but I don't really want to have to make a separate Math server running in the background just for these benefits! Furthermore, the IPC message-passing overhead (both computation and latency) is certain to be pretty huge compared to direct procedure calls.

Are there any languages that provide this kind of modularity within a process? As an in between before the tight-coupling of direct procedure-calls and the overhead of a multi-process client-server design? The way I envision it, instead of :

y = Math.sin(x)

which leaves me open to infinite loops and stack-overflows in the Math module, I would like to do something like

y = try(maxMemory=1024kb, maxTime=12ms){
    Math.sin(x)
}catch(Anything){
    0
}

Which would set y to a default value (0) if anything fails within Math.sin. Invalid input, bugs, infinite loops, runtime-exceptions, anything. Does anything like this exist already in some language, and if not, why? It seems to me like something that would be immensely useful, in a wide variety of places.

Li Haoyi
  • 15,330
  • 17
  • 80
  • 137
  • You're trying to implement something in process space which is done best by the OS... Maybe there's a language out there which does something similar what you're looking for, but if there is, it's almost definitely implements these features with creating multiple processes.. so you would have the same overhead, but the language would take care for all the boilerplate code. Another solution would be to use a VM layer, in which you can have your own virtual processes, scheduler... but agian, that will kill performance. – Karoly Horvath Mar 01 '12 at 01:08

1 Answers1

1

You can do this in Racket using the sandbox library:

> (require racket/sandbox)
> (define x 0) ;; some input value
> (call-with-limits 0.012 ;; 12 ms
                    1     ;; 1 MB
                    (lambda () (sin x)))
0

> (call-with-limits 1 ;; 1 sec
                    1 ;; 1 MB
                    (lambda () (sleep 2) 'done))
with-limit: out of time

> (call-with-limits #f ;; no time limit
                    1  ;; 1 MB
                    (lambda () 
                      (let loop () 
                        (cons (make-vector 10000) (loop)))))
with-limit: out of memory

The code is run in a separate lightweight Racket ("green") thread (not a separate OS process).

The last two cases raise exceptions, which you can catch if you want to substitute an alternative value.

Using the sandbox library you can also do more powerful things like set up evaluators that restrict access to a small number of approved libraries, restrict filesystem and network access, etc.

On the other hand, this is more expensive than a normal function call. In practice, you need to figure out which components you trust and which ones you don't. Or perhaps you should look at systems that support static verification of your additional requirements.

Ryan Culpepper
  • 10,495
  • 4
  • 31
  • 30