-1

Many operating systems allow one to memory map files, and read from them lazily. If the operating system can do this then effectively it has the power to create regular pointers out of thunks.

Does any operating system allow an application programmer to create pointers out of his own thunks?

I know that to a limited extent operating systems already support this capability because one can create a pipe, map it into memory, and connect a process to the pipe to accomplish some of what I'm talking about so this functionality doesn't seem too impossible or unreasonable.

A simple example of this feature is a pointer which counts the number of times it's been dereferenced. The following program would output zero, and then one.

static void setter(void* environment, void* input) {
 /* You can't set the counter */
}

static void getter(void* environment, void* output) {
  *((int*)output) = *((int*)environment)++;
}

int main(int argc, char** argv) {
 volatile int counter = 0;
 volatile int * const x = map_special_voodoo_magic(getter, setter, sizeof(*x),
                                                   &counter);

 printf("%i\n", *x);
 printf("%i\n", *x);

 unmap_special_voodoo_magic(x);
}

P.S. A volatile qualifier is required because the value pointed to by x changes unexpectedly right? As well, the compiler has no reason to think that dereferencing x would change counter so a volatile is needed there too right?

Mysticial
  • 464,885
  • 45
  • 335
  • 332
  • 2
    `If the operating system can do this then effectively it has the power to create regular pointers out of thunks` -- Huh? – Robert Harvey Aug 24 '12 at 22:23
  • @RobertHarvey A thunk is a lazily evaluated piece of data. A memory mapped file is read lazily. Therefore a memory mapped file is a stream of thunks and there's also a pointer to it. – Molly Stewart-Gallus Aug 24 '12 at 22:24
  • There's something wrong with your logic there. It's a little bit like saying dogs are man's best friend, everyone needs a friend, so everyone should have a dog. – Robert Harvey Aug 24 '12 at 22:27
  • @RobertHarvey Maybe I'm being a bit unclear but I hope I'm getting the point across that the operating system has the power to make lazily evaluated data and that I want to know if the application programmer has the power to do that as well (with it having the interface of a pointer.) – Molly Stewart-Gallus Aug 24 '12 at 22:30
  • 1
    @Steven Stewart-Gallus With C, you can't do this through pointers only, you'll have to invoke functions, not dereference pointers. With C++ you can though, through your own smart pointer. (You could perhaps do something similar in C on some platforms by trapping SIGSEGV and doing an mmap() in the signal handler -which would not be worth the trouble.) – nos Aug 25 '12 at 20:41
  • The term "thunk" is a very generic interop term and can mean many things. You are hoping for a universal definition that can work in many runtime environments, even to the point that an OS can take care of it. There is none, even mapping a structure to shared memory is rife with implementation details. You say "thunk" when you prefer to not have to deal with that. – Hans Passant Aug 25 '12 at 21:05
  • @nos Trapping SIGSEGV was exactly the kind of thing I was thinking about. I think I'll try that. (About not just using a smart pointer, what if one has to interface with old code or otherwise limited code which only accepts regular pointers?) – Molly Stewart-Gallus Aug 25 '12 at 22:07
  • @nos I've been trying the trapping SIGSEGV approach for an hour now, and I keep getting MAP_FAILED errors, and problems in the signal handler. Can you point me to any resources? – Molly Stewart-Gallus Aug 25 '12 at 23:04

1 Answers1

1

The following code has no error checking, and is not a complete implementation. However, the following code does illustrate the basic idea of how to make a thunk into a pointer. In particular, the value 4 is calculated on demand and not assigned to memory earlier.

#include <stdlib.h>
#include <stdio.h>
#include <sys/mman.h>
#include <signal.h>

void * value;

static void catch_function(int signal, siginfo_t* siginfo,
                 void* context) {
    if (value != siginfo->si_addr) {
        puts("ERROR: Wrong address!");
        exit(1);
    }

    mmap(value, sizeof(int), PROT_READ | PROT_WRITE, MAP_FIXED | MAP_SHARED
                        | MAP_ANON, -1, 0);

    *((int*)value) = 2 * 2;
}

int main(void) {
    struct sigaction new_action;

    value = mmap(NULL, sizeof(int), PROT_NONE, MAP_ANON | MAP_SHARED, -1,
                    0);

    sigemptyset(&new_action.sa_mask);

    new_action.sa_sigaction = catch_function;
    new_action.sa_flags = SA_SIGINFO;

    sigaction(SIGBUS, &new_action, NULL);

    printf("The square of 2 is: %i\n", *((int*)value));

    munmap(value, sizeof(int)); 

    return 0;
}