What happens at the machine level when you attach an event handler?

chrstrbrts

Senior member
Aug 12, 2014
522
3
81
Hello everyone,

OK.

So what I mean by my question is let's say I use Javascript or Java or some other high level language to attach an event handler to some object.

In Javascript, using Jquery for example, I might code something like:

$( "#target" ).click(function() {
<code goes here>
});

to attach an event handler that handles mouse clicks on a DOM element.

Similarly, Java has a mouse-listener interface that you can use.

Now, at the machine level, mouse clicks should engender hardware interrupts.

Further, hardware interrupts should be handled by interrupt handlers that are apart of the OS that you are using.

Obviously, these handlers are coded and compiled beforehand, and they are presented to the user as they are.

You can't change them (as far as I know).

So, when I attach an event listener to an object, how is my high level code interacting with the low-level kernel interrupt handling code?

Thanks.
 
Last edited:

Merad

Platinum Member
May 31, 2010
2,586
19
81
1. CPU receives an interrupt that mouse data is available
2. CPU calls OS interrupt handler
3. OS interrupt handler forwards the mouse data to the mouse driver
4. Mouse driver interprets the raw data and tells the OS what movement has happened, button clicked, etc
5. OS sends a message to the program (let's assume Java) that currently has focus and is receiving mouse events
6. The the program has code (built into the JVM, for a Java program) that reads messages from the OS and determines that a mouse event has happened
7. The JVM notifies all listeners for mouse events

I'm throwing educated guesses in there because I don't know many details about how mouse drivers work, but it gives you the rough idea.

Edit: Just to be clear, nothing happens at the hardware level when you bind to events in a user program. You're attaching to mechanisms built into your language/framework, which in turn attaches to the OS, which deals with the hardware.
 
Last edited:

chrstrbrts

Senior member
Aug 12, 2014
522
3
81
5. OS sends a message to the program (let's assume Java) that currently has focus and is receiving mouse events

Thanks for the info.

But, how does the OS know which process has the focus?

Is there a flag set in the process's PCB?

Thanks.
 

Merad

Platinum Member
May 31, 2010
2,586
19
81
I have no clue. I'm guessing the typical OS uses something like a modified quadtree to partition the screen and detect which windows receive focus from a mouse click. A normal quadtree is just 2d, you would need add some kind of layering or z-depth component to account for windows covering one another. Where/if it is stored and how often going to be details of the implementation.
 

Gryz

Golden Member
Aug 28, 2010
1,551
204
106
It's the Windowing-system that keeps track of where the mouse-pointer is, and where the focus is. It also keeps track of which windows are opened on the screen, which ones are iconified, how they are stacked, etc.

Most Unix and Linux systems use the X Window System. KDE and Gnome are built on top of X11. I believe Macs have their own flavor of X11. Microsoft uses something else, that is integrated into their OSs (I don't know if it even has a name). In the X Window System, there is a separate process that does all the drawing on your screen. That is called the X Window Server. Usually there is a separate process that manages how windows on the screen are moved, iconified or stacked. That program is called the "window manager". In Windows this is called DWM, for Unix there are many window managers you can pick from. (Although I guess KDE and Gnome come with their own window manager).

Schema_of_the_layers_of_the_graphical_user_interface.svg


So how it works is:
hardware generates an interrupt.
kernel receives the interrupt.
kernel sends a message to the X Display Server.
the X Display Server looks where the mouse location was, or which window had the focus
the X Display Server sends a message to the process that owns that window. or to the window manager (if the click was outside all windows, or on a title-bar).
 

chrstrbrts

Senior member
Aug 12, 2014
522
3
81
Thanks, guys. That was very informative.

But, now I have a slightly different question.

Everything comes down to opcodes run on a processor. Everything.

Let's say I want to use assembly, not a high level language, to code a program that runs asynchronously.

Consider the following simple assembly program:

I want to initialize two registers. Then, I want the program to wait for the left mouse button to be clicked anywhere (location is not important). While it's waiting, it does nothing. When the mouse interrupt is handled, I want to add the two registers together and exit.

Off the top of my head, I have:

mov eax, 1
mov ebx, 2

{wait for interrupt from left mouse button. when interrupt is raised call procedure 'add_numbers'}

main end

add_numbers proc
add eax, ebx
add_numbers endp

My question then is how do I code the middle area where I tell the program to listen for a mouse event?

I don't want a JVM or Javascript backend engine to rely on. I want to do this all on my own. However, I'm unsure of what opcodes relate to asynchronous event handling.

Thanks.
 
Last edited:

Merad

Platinum Member
May 31, 2010
2,586
19
81
It would work exactly like in a low level C or C++ program, you are just using assembly to call the OS functions that deal with receiving input.

If you're talking about writing everything yourself in assembly, you can't, not in a user mode application. You essentially want to write your own OS. I'd suggest starting here http://wiki.osdev.org/Main_Page
 

chrstrbrts

Senior member
Aug 12, 2014
522
3
81
It would work exactly like in a low level C or C++ program, you are just using assembly to call the OS functions that deal with receiving input.

I'm familiar with the idea of calling functions provided to you by the OS's API. You do this whenever you want your user-space process to access a peripheral I/O device. This is called a software interrupt.

Though, my understanding is that this is an inherently synchronous paradigm. Example:

create string_1 in RAM
move pointer to string_1 into register eax
call kernel function writeToScreen and pass eax to it

So, I'm not exactly sure what you mean by using a software interrupt to handle asynchronicity.

Are you saying that there is a function that a user-space process can call that will attach a user-space procedure to a hardware interrupt handler?

Please, explain further.


Great link. Thanks.
 

sm625

Diamond Member
May 6, 2011
8,172
137
106
There are many ways to capture a mouse click. You could wait for Windows to send a message to your application if you are only interested in capturing clicks relevant to your application, such as a dialog based app. That is what you might call a high level event handler. OR you could capture all the mouse events and process all of them before sending them along to their intended destination. That would be a low level event handler. An example of that would be tools that allow you to remap mouse buttons. I just installed such a tool yesterday because I have a mouse that has a tilt click feature on the mouse wheel. Tilting left is the same as clicking the browser's back button. I found that to be highly annoying since I often click the mouse wheel to open links in a new tab and sometimes it would click and tilt at the same time.
 

Merad

Platinum Member
May 31, 2010
2,586
19
81
Are you saying that there is a function that a user-space process can call that will attach a user-space procedure to a hardware interrupt handler?

No, the opposite. A user mode program doesn't have access to hardware interrupts.

A basic program to do what you were talking about would like something like this (pseudo-C, not based on any particular OS):

Code:
int a;
int b;
int exitFlag = 0;

int add();
void processMessage(OsMessage* msg);

int main()
{
  // this is a type defined by the OS
  OsMessage msg;

  a = 1;
  b = 2;
  
  while (!exitFlag)
  {
    // this is an OS function
    // it immediately returns false if no message is ready
    if (readOsMessage(&msg))
      processMessage(&msg);

    // os function, yield the cpu to other programs
    sleep(1);
  }
}

int add()
{
  printf("%d", a + b);
  exitFlag = 1;
}

void processMessage(OsMessage* msg)
{
  if (msg->type == EXIT_MSG)
  {
    exitFlag = 1;
  }
  else if (msg->type == MOUSE_CLICK_MSG && msg->data == LEFT_MOUSE_CLICK)
  {
    add();
  }
}

An assembly program would do all the same basic stuff, just calling the readOsMessage function and dealing with the messages in assembly.
 
Last edited:

Cogman

Lifer
Sep 19, 2000
10,283
135
106
Thanks, guys. That was very informative.

But, now I have a slightly different question.

Everything comes down to opcodes run on a processor. Everything.

Let's say I want to use assembly, not a high level language, to code a program that runs asynchronously.

Consider the following simple assembly program:

I want to initialize two registers. Then, I want the program to wait for the left mouse button to be clicked anywhere (location is not important). While it's waiting, it does nothing. When the mouse interrupt is handled, I want to add the two registers together and exit.

Off the top of my head, I have:

mov eax, 1
mov ebx, 2

{wait for interrupt from left mouse button. when interrupt is raised call procedure 'add_numbers'}

main end

add_numbers proc
add eax, ebx
add_numbers endp

My question then is how do I code the middle area where I tell the program to listen for a mouse event?

I don't want a JVM or Javascript backend engine to rely on. I want to do this all on my own. However, I'm unsure of what opcodes relate to asynchronous event handling.

Thanks.

It is sort of a mixture of things going on. For a strictly GUI app with no graphical elements (not a 3d game), you'll usually have some soft of event loop which calls an OS method which waits for new events to come in. The method will block until the OS notifies it to run. The OS will push the events into an event buffer (and manage which events go to which application event buffer) and it will start the application running when the events happen and handle the pausing of the application when no events are available.

So in user land, you would simply call the "GetMessage" function from the OS library and that would cause your app to sleep if nothing is there or grab the next message on the queue (all handled in OS land). How that works exactly is going to depend on the OS.
 

K7SN

Senior member
Jun 21, 2015
353
0
0
In programming a (not with) synchronous (time) have a much different meaning than networking signaling which might be stated as not with the same time or rate (both time related).

The little multi-colored button typically in the lower left corner of your display on a desktop monitor is an asynchronous (not with time); independent of other processes. When you move several files around using Windows Exploder the little progress popup that starts if the job isn't completed quickly, remains and runs until the job is completed is an example of a synchronous operation (with time, one follows another) means that the process runs only as a result of some other process being completed or handing off operation. The running program allows, at intervals, the popup to update and display progress.

Unless I am mistaken both are still handled the same at a lowest-level. They were 40 years ago when I programmed at that level; the confusion lies with the different meaning of asynchronous when talking about network(s) signals (different clock rates versus same rate synchronicity).
 

Cogman

Lifer
Sep 19, 2000
10,283
135
106
In programming a (not with) synchronous (time) have a much different meaning than networking signaling which might be stated as not with the same time or rate (both time related).

The little multi-colored button typically in the lower left corner of your display on a desktop monitor is an asynchronous (not with time); independent of other processes. When you move several files around using Windows Exploder the little progress popup that starts if the job isn't completed quickly, remains and runs until the job is completed is an example of a synchronous operation (with time, one follows another) means that the process runs only as a result of some other process being completed or handing off operation. The running program allows, at intervals, the popup to update and display progress.

Unless I am mistaken both are still handled the same at a lowest-level. They were 40 years ago when I programmed at that level; the confusion lies with the different meaning of asynchronous when talking about network(s) signals (different clock rates versus same rate synchronicity).

In the programming world, asynchronous is simply stuff that happens outside of the regular control flow. It is somewhat related to the notion of blocking vs non-blocking. It is also somewhat related to the notion of concurrency (but not necessarily parallelism).

Asynchronous stuff in the programming world isn't necessarily a low level concept. Things like Futures, Actors, and Events are all programming concepts that deal with asynchronous behavior in a higher level construct.

The hardware definition of asynchronous is different. In those realms it pretty much means "running without a clock". In other words, a clock is used to synchronize steps and actions and to split them into stages of computation. Those stages are usually asynchronous with the guarantee that all transistors will be in a stable state by the time the next clock rolls around.

The networking definition is even more different. It is less "running without a clock" an more "running with an embedded clock". In other words, the clock is part of the data signal rather than a separate line. There is often still some concept of timing and clock negotiating going on, there just isn't some separated signal dedicated solely to switching on and off at some rate.
 

chrstrbrts

Senior member
Aug 12, 2014
522
3
81
You could wait for Windows to send a message to your application if you are only interested in capturing clicks relevant to your application...

Yes, that's my question. How do you accomplish that on the machine level?

Code:
int main()
{
  // this is a type defined by the OS
  OsMessage msg;

How is this translated into assembly?

If I want to declare "regular" variables in higher level languages, those declarations translate pretty clearly into assembly:

int a; in C or Java is the same as:

a DWORD ? in MASM

How do I code for OS defined types in assembly?

I know that if I want to call an OS defined function in its API, I need to issue a software interrupt and tap into kernel space.

But, what about kernel space data?

After all, an API is both functions and data.

Do I need to issue a software interrupt to access protected kernel memory locations like an interrupt message that has been placed into an interrupt message queue?

Code:
while (!exitFlag)
  {
    // this is an OS function
    // it immediately returns false if no message is ready
    if (readOsMessage(&msg))
      processMessage(&msg);

    // os function, yield the cpu to other programs
    sleep(1);
  }

This looks like polling to me.

Code:
if (msg->type == EXIT_MSG)

else if (msg->type == MOUSE_CLICK_MSG && msg->data == LEFT_MOUSE_CLICK)

I think that these are struct elements in C.

Again, how do I point to these OS defined data structures?

I'll assume that wherever the pertinent data may be stored, it's the mouse driver that decides the form of the data.

Example:

If the left button was clicked, then the pertinent byte is 00h.

If it's the right button, then the pertinent byte is 01h.

For a strictly GUI app with no graphical elements (not a 3d game)...

Why would 3d graphics change anything?

OK.

Thanks for all of your input.

My understanding now is that you can not directly handle hardware interrupts from user space.

You must poll periodically to determine if the OS has passed anything into some sort of user space accessible common memory area.
 
Last edited:

Cogman

Lifer
Sep 19, 2000
10,283
135
106
Why would 3d graphics change anything?

OK.

Thanks for all of your input.

My understanding now is that you can not directly handle hardware interrupts from user space.

You must poll periodically to determine if the OS has passed anything into some sort of user space accessible common memory area.

Events come in when they come in, they don't necessarily happen at each frame of the application. So blocking rendering on the event queue would be a bad thing, it would result in you not seeing anything happen on the screen until someone moves the mouse, types a key, or resizes the window.

In that case, you still want to pull off all the events, but you don't want to block and wait for the events come in. AFAIK, all OSes provide a way for you to do that simply peeking and popping off of the event queue new events.

For a standard gui application, this is fine, you don't redraw things very frequently. For a 3d app like a game, you need to redraw at pretty much every frame (or at least some divisor of the monitor refresh rate). Though, you could get away from that if you are doing something like modeling software. In that case you only need to redraw if someone changes the scene being rendered.
 

Merad

Platinum Member
May 31, 2010
2,586
19
81
If I want to declare "regular" variables in higher level languages, those declarations translate pretty clearly into assembly:

Variables are memory. You allocate memory, and you have a variable. Structs are just contiguous bytes of memory. If you have a struct like

Code:
struct Foo
{
  int a;
  int b;
  int c;
}

then to create a "Foo" (assuming your target is IA32) you need to allocate 12 bytes of memory somewhere. If the address of your "Foo" is X, then the address of X is equivalent to Foo->a. X+4 is Foo->b, and X+8 is Foo->c. However, you have to know the padding and alignment requirements for your platform to ensure that you create and access the struct correctly. That's the price you pay for using assembly.

This looks like polling to me.

Yes, basically. I'm not very familiar with GUI applications on Linux or Mac, but that's 100% the standard on windows. When you use an event driven GUI framework like Java Swing, WinForms, WPF, etc, the framework is just hiding the message loop from you (and dispatching events as messages come in). For example in a WinForms/C# application you can write your own main loop if say you're writing a game, but you have to call System.Windows.Forms.Application.DoEvents() regularly to clear the message queue or else your program will "freeze" because it isn't receiving messages.
 
Last edited:

chrstrbrts

Senior member
Aug 12, 2014
522
3
81
Variables are memory. You allocate memory, and you have a variable. Structs are just contiguous bytes of memory. If you have a struct like

Code:
struct Foo
{
  int a;
  int b;
  int c;
}

then to create a "Foo" (assuming your target is IA32) you need to allocate 12 bytes of memory somewhere. If the address of your "Foo" is X, then the address of X is equivalent to Foo->a. X+4 is Foo->b, and X+8 is Foo->c. However, you have to know the padding and alignment requirements for your platform to ensure that you create and access the struct correctly. That's the price you pay for using assembly.



Yes, basically. I'm not very familiar with GUI applications on Linux or Mac, but that's 100% the standard on windows. When you use an event driven GUI framework like Java Swing, WinForms, WPF, etc, the framework is just hiding the message loop from you (and dispatching events as messages come in). For example in a WinForms/C# application you can write your own main loop if say you're writing a game, but you have to call System.Windows.Forms.Application.DoEvents() regularly to clear the message queue or else your program will "freeze" because it isn't receiving messages.

Thank you. Very informative.

However, I was hoping that you could answer my other question.

Regarding the OS defined type, the OsMessage in your example, how do I point to it in assembly?

In your pseudo C example, you passed a pointer to that type into an OS function that checked for messages in the queue.

As you know, in assembly, there is no such thing as passing a variable to a function.

Instead, you pass data or a pointer to data into a location where the called routine expects to find it.

This is part of the called routine's specification.

So, I need to know where to look to find this data.

Where would the OsMessage live in memory?

How do I get its address?

Also, when the data associated with an interrupt is finally returned, it contains certain information encoded in a predetermined way.

Example: If the left mouse button was clicked, then the first byte in the message struct looks like 10011001.

Who decides what form this data takes? The device driver?
 

Merad

Platinum Member
May 31, 2010
2,586
19
81
Where would the OsMessage live in memory?

Wherever you put it. The typical options are on the stack, in the heap, or in a static data section. The C pseudo code above would translate to something like

Code:
// assume OsMessage is 8 bytes and pointers are 4 bytes
sub 0xc, %esp
// calculate the struct address and store the pointer for the function argument
lea 0x8(%esp), %eax
mov %eax, (%esp)
call readOsMessage

How do I get its address?

Either calculate it (as above) or use the features of your assembler to get its address if it's statically allocated.

Also, when the data associated with an interrupt is finally returned, it contains certain information encoded in a predetermined way.

Example: If the left mouse button was clicked, then the first byte in the message struct looks like 10011001.

Who decides what form this data takes? The device driver?

If you're referring to the hypothetical readOsMessage function, it's best referred to as a system call. To be pedantic, the function invokes a software interrupt in order to perform a system call. Just saying interrupt quickly becomes confusing since there are a multitude of hardware and software interrupts.

Re the data. It probably just depends. I would assume there are some standards (whether formal or de facto, I don't know) for certain types of devices since we have things like "generic mouse driver" and "generic keyboard driver". Most likely in devices with advanced features the OS forwards the raw data to the driver for interpretation.
 

chrstrbrts

Senior member
Aug 12, 2014
522
3
81
Wherever you put it. The typical options are on the stack, in the heap, or in a static data section. The C pseudo code above would translate to something like

Code:
// assume OsMessage is 8 bytes and pointers are 4 bytes
sub 0xc, %esp
// calculate the struct address and store the pointer for the function argument
lea 0x8(%esp), %eax
mov %eax, (%esp)
call readOsMessage

OK, now I'm confused.

Here is my understanding; show me where I'm wrong:

The CPU will check the interrupt pin at the end of its cycle.

If it's high, there is communication with the interrupt controller, an interrupt handler which is part of the OS is evoked, and communication with a driver takes place.

When the OS finally knows which device issued the hardware interrupt and acquires all of the information, it passes this data to some kind of "mailbox", an area in RAM where processes can pick up data left for them by the OS.

My question is: if I'm writing an application in assembly, I need to issue a software interrupt every X milliseconds and tell the kernel code I'm calling out to to check the mailbox location in RAM and tell me if data of the appropriate form is stored there.

What is that address?

The builder of the OS should have set it, not me the lowly application programmer.

Your explanation suggests that the application programmer somehow has control over that location, that he can just set it to whatever he wants.

But if my understanding of the entire scenario is correct, I don't see how the application programmer has any control over that at all.

If you're referring to the hypothetical readOsMessage function, it's best referred to as a system call. To be pedantic, the function invokes a software interrupt in order to perform a system call. Just saying interrupt quickly becomes confusing since there are a multitude of hardware and software interrupts.

With respect to the data, I was talking about the hardware interrupt.

The left button being pressed must map to some data expression e.g. 11001010.

Who decides this?

The driver? The interrupt handler?
 

Gryz

Golden Member
Aug 28, 2010
1,551
204
106
This is why people write APIs.

Nowadays there are layers upon layers of abstraction. Especially when dealing with window-systems. Either you make use of the calls that the APIs give you. Or you program your own stuff, but it will end up being *exactly* the same as what the API-calls do.

The only way to get notification from the OS that someone clicked a mouse button, is by doing exactly the same thing was what the API-calls do. Recreating that from scratch is not only a lot of work, it seems pointless to me too. You're not gonna gain anything by trying to circumvent windowing-APIs.
 

Exophase

Diamond Member
Apr 19, 2012
4,439
9
81
OK, now I'm confused.

Here is my understanding; show me where I'm wrong:

The CPU will check the interrupt pin at the end of its cycle.

If it's high, there is communication with the interrupt controller, an interrupt handler which is part of the OS is evoked, and communication with a driver takes place.

When the OS finally knows which device issued the hardware interrupt and acquires all of the information, it passes this data to some kind of "mailbox", an area in RAM where processes can pick up data left for them by the OS.

My question is: if I'm writing an application in assembly, I need to issue a software interrupt every X milliseconds and tell the kernel code I'm calling out to to check the mailbox location in RAM and tell me if data of the appropriate form is stored there.

What is that address?

The builder of the OS should have set it, not me the lowly application programmer.

Your explanation suggests that the application programmer somehow has control over that location, that he can just set it to whatever he wants.

But if my understanding of the entire scenario is correct, I don't see how the application programmer has any control over that at all.



With respect to the data, I was talking about the hardware interrupt.

The left button being pressed must map to some data expression e.g. 11001010.

Who decides this?

The driver? The interrupt handler?

Maybe it'll help if I explain using a somewhat more direct, lower level, less abstracted example. Let's say I have a program and I want to read directly from something that the kernel manages like a terminal, which maybe represents reading keyboard input or data off of a serial port. In Linux and other Unix-like OSes this communication is managed through files.

Here's a flow of what basically happens:

1) The user program sends the system call "open" with a filesystem location of where the device file is. For example:

Code:
int fd = open("/dev/ttyS0");

The specifics of what this means in assembly language depends on the details of the instruction set and how the OS works. It'll probably involve putting the arguments in registers and using some sort of system call instruction. Then the result will be returned in some register.

2) The kernel looks up the file path, sees that it's attached to a device driver, and hands over control to an open function registered with the device driver. The device driver does whatever initialization stuff is necessary for opening and returns to the kernel.

3) The kernel returns to the program a number identifying the open file.

4) The program sends a "read" syscall to the kernel to ask for data from the device, like so:

Code:
read(fd, my_data, 4);

What this means is you want to read 4 characters from the device. Now what actually happens from here depends on the device and how it's configured. It might immediately return only the data it currently has (which could be nothing). Or it might stop and wait for data to arrive. I'm going to go with the later style (blocking access) because it seems more in line with the questions you were asking earlier.

5) The kernel sees that you want to read from the device opened with the descriptor in fd and calls the read function registered by the driver. The driver looks to see if it has 4 characters ready and it turns out it only has 3, so it tells the kernel to put the process to sleep.

6) The process yields control back to the kernel which can schedule another process (or do nothing if nothing is waiting to be run, in which case it probably puts the CPU in a low power state). The process is put in a sleeping state and won't be ran again until something changes that.

7) The user presses a key and an interrupt fires in the CPU. Control switches to the kernel's interrupt handler, which looks up the interrupt and finds that it's registered to the terminal driver, so it calls the driver's interrupt handler function.

8) The driver sees that the outstanding read syscall can now be completed. So it takes the data off of its buffer and puts it in the array the process told it to put it in with the read syscall. Then it tells the kernel to wake up the reading process, which puts it in the runnable state.

9) The kernel's scheduler runs the process again, which continues execution from where the read syscall left off.

You can see here that the kernel abstracts things like raw memory locations from the program, except where it's the program's managed memory (like the buffer to write the data to), in which case the program tells the kernel that location.

I don't really know the low level details of how something like X11 is implemented but it could work by having the window manager process read from some kernel devices that handle various I/O in a way much like what I described (maybe using non-blocking reads, maybe using different threads, etc). Then it could implement the event queues for different windows via something like sockets/named pipes which are files that are created process to process communication. Then the user application reads from the socket and just like with reading from a device, the OS will put the program to sleep if it's in blocking mode.
 

Merad

Platinum Member
May 31, 2010
2,586
19
81
When the OS finally knows which device issued the hardware interrupt and acquires all of the information, it passes this data to some kind of "mailbox", an area in RAM where processes can pick up data left for them by the OS.

My question is: if I'm writing an application in assembly, I need to issue a software interrupt every X milliseconds and tell the kernel code I'm calling out to to check the mailbox location in RAM and tell me if data of the appropriate form is stored there.

You're fundamentally misunderstanding how the operating system sits between a user program and things like interrupts. You cannot access the DMA location in memory. It's impossible. Even if you knew the address, it's meaningless in your program because you are sandboxed by the virtual memory system. You may know that the DMA buffer sits at 0xDEADBEEF, but accessing 0xDEADBEEF from within your program may actually map to 0x12345678. Or 0xAABBCCDD. You have no way of knowing, and it doesn't matter if you do know because the kernel will not allow you to access a protected memory region like a DMA buffer.

Even a kernel mode driver can't access these things directly (on Windows, at least). You're forced to go through a DMA library provided by the OS.

As Gryz said, even the low level facilities like "readOsMessage" are already a good 4-5 layers of abstraction away from the bare interrupt and DMA.

Like I said before, things you're wanting to do are only possible when writing your own operating system.
 

chrstrbrts

Senior member
Aug 12, 2014
522
3
81
You're fundamentally misunderstanding how the operating system sits between a user program and things like interrupts. You cannot access the DMA location in memory. It's impossible. Even if you knew the address, it's meaningless in your program because you are sandboxed by the virtual memory system. You may know that the DMA buffer sits at 0xDEADBEEF, but accessing 0xDEADBEEF from within your program may actually map to 0x12345678. Or 0xAABBCCDD. You have no way of knowing, and it doesn't matter if you do know because the kernel will not allow you to access a protected memory region like a DMA buffer.

I understand this.

I'm fully aware that the OS keeps user space activity from accessing certain areas of the memory and abstracts away things like physical RAM locations.

I understand that that is the whole point of an OS: Force user space entities to ask permission from the OS to access the finite and limited number of I/O devices available lest data corruption occurs.

As Gryz said, even the low level facilities like "readOsMessage" are already a good 4-5 layers of abstraction away from the bare interrupt and DMA.

OK. Well, remember in your pseudo C example how you passed a pointer to the interrupt message to the kernel space message reader function?

All I'm asking is where does that pointer point?

When you typed this 2 posts ago:

Wherever you put it. The typical options are on the stack, in the heap, or in a static data section.

You lead me to believe that I had some sort of control over the message location.

The high level C code makes perfect sense, but I'm not interested in higher languages.

I'm only interested in assembly.

Like I said before, things you're wanting to do are only possible when writing your own operating system.

By the way, I'm not asking all of these questions because I actually intend to code any of this myself.

I'm simply interested in understanding exactly how the machine works.

Sorry for the headaches, but you have to understand that I'm obsessed.

I'm reading >100 pages of text every day on architecture, OSs, etc. and fall asleep thinking about page frames.
 
Last edited:

Merad

Platinum Member
May 31, 2010
2,586
19
81
You lead me to believe that I had some sort of control over the message location.

Absolutely, yes. When you pass a pointer you say "here is a memory location I want you to write to".

The OsMessage struct and readOsMessage function have absolutely nothing whatsoever to do with the mouse input interrupts, mouse DMA buffer, or mouse driver, perhaps that is where you're confused? Those raw input actions go through 4-5 layers of abstraction in the OS and driver, and if the mouse is active in your window the OS will notify your program by sending you a message (the OsMessage).

Let's abandon the hypothetical and look at a real but utlra bare bones Windows GUI program:

Code:
LONG APIENTRY MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

// this is the "main" function
INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, INT nCmdShow)
{  
  // this is a user defined function
  // all we need to know is that it hooks the function MainWndProc as
  // the handler for messages posted to our program window
  if (!initInstance(hInst, nCmdShow))
    return 1;
    
  MSG msg;
  // retrieve a message from the OS queue
  while (GetMessage(&msg, NULL, 0, 0) > 0)
  {
    // translates a "keydown" message to a "character" (text) message
    TranslateMessage(&msg);
    // send the message to be handled by the window process (MainWndProc)
    DispatchMessage(&msg);
  }

  return msg.wParam;
}

LONG APIENTRY MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  switch (msg)
  {
  case WM_LBUTTONDOWN:
    // do stuff when left mouse pressed
    break;
    
  case WM_MOUSEMOVE:
    // do stuff when mouse moves
    break;    
    
  case WM_CHAR:
    // do stuff for text input
    break;
    
  case WM_PAINT:
    // redraw the GUI
    break;
        
  case WM_DESTROY:
    // window closed, exit
    PostQuitMessage(0);
    break;
    
  // many, many more
  }
  
  return 0;
}

Windows defines the MSG struct as

Code:
typedef struct tagMSG {
  HWND   hwnd;
  UINT   message;
  WPARAM wParam;
  LPARAM lParam;
  DWORD  time;
  POINT  pt;
} MSG;

Every single possible type of input to your program or user/OS interaction with your program comes in as a MSG and is stuffed into some combination of those 6 fields. Windows defines hundreds if not thousands of different kinds of messages that you can explore through this list.
 

chrstrbrts

Senior member
Aug 12, 2014
522
3
81
Absolutely, yes. When you pass a pointer you say "here is a memory location I want you to write to".

The OsMessage struct and readOsMessage function have absolutely nothing whatsoever to do with the mouse input interrupts, mouse DMA buffer, or mouse driver, perhaps that is where you're confused? Those raw input actions go through 4-5 layers of abstraction in the OS and driver, and if the mouse is active in your window the OS will notify your program by sending you a message (the OsMessage).

Let's abandon the hypothetical and look at a real but utlra bare bones Windows GUI program:

Code:
LONG APIENTRY MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);

// this is the "main" function
INT WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, INT nCmdShow)
{  
  // this is a user defined function
  // all we need to know is that it hooks the function MainWndProc as
  // the handler for messages posted to our program window
  if (!initInstance(hInst, nCmdShow))
    return 1;
    
  MSG msg;
  // retrieve a message from the OS queue
  while (GetMessage(&msg, NULL, 0, 0) > 0)
  {
    // translates a "keydown" message to a "character" (text) message
    TranslateMessage(&msg);
    // send the message to be handled by the window process (MainWndProc)
    DispatchMessage(&msg);
  }

  return msg.wParam;
}

LONG APIENTRY MainWndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  switch (msg)
  {
  case WM_LBUTTONDOWN:
    // do stuff when left mouse pressed
    break;
    
  case WM_MOUSEMOVE:
    // do stuff when mouse moves
    break;    
    
  case WM_CHAR:
    // do stuff for text input
    break;
    
  case WM_PAINT:
    // redraw the GUI
    break;
        
  case WM_DESTROY:
    // window closed, exit
    PostQuitMessage(0);
    break;
    
  // many, many more
  }
  
  return 0;
}

Windows defines the MSG struct as

Code:
typedef struct tagMSG {
  HWND   hwnd;
  UINT   message;
  WPARAM wParam;
  LPARAM lParam;
  DWORD  time;
  POINT  pt;
} MSG;

Every single possible type of input to your program or user/OS interaction with your program comes in as a MSG and is stuffed into some combination of those 6 fields. Windows defines hundreds if not thousands of different kinds of messages that you can explore through this list.

Where is the address for the message queue? That's what I want to know. You keep passing pointers to the message to functions that will read / interpret the message. Where do those pointers point?

I understand that you can't access the DMA controller or talk to the driver directly in user space. I also understand that by the time you get the message, the OS has done quite a bit of work behind the scenes.

But, in the end, the message is dropped somewhere in RAM for the process to handle. Where?

If I'm to write this code in assembly, I need to have some way of knowing what that address is.

Unless, the msg variable is data that exists in some library that is part of the API that the OS provides and I just link to the library and call the variable out by name.

Is that it?