Speaker 1: Welcome to the deep dive. Today. We're really peeling back
Speaker 1: the layers of your Windows ten computer.
Speaker 2: Yeah, going straight to the core.
Speaker 1: Exactly how software actually interacts with the operating system. One
Speaker 1: of you asked for a deeper look, and well, here.
Speaker 2: We are, absolutely and we've got a really good technical
Speaker 2: book to guide us. We'll be digging into the key
Speaker 2: insights on the fundamental stuff.
Speaker 1: Like processes, threads.
Speaker 2: Right, memory management, and that crucial world of IO input
Speaker 2: output operations.
Speaker 1: Our mission then for this deep dive is to get
Speaker 1: right to the heart of how Windows actually juggles all
Speaker 1: the programs you run and the resources they all need.
Speaker 2: We're aiming for those moments where it just clicks.
Speaker 1: Yeah, those aha moments where you think, oh, that's why
Speaker 1: my system does that. So let's start at the very
Speaker 1: beginning processes.
Speaker 2: Okay, so book right away makes this really important point.
Speaker 2: It might even surprise you. We usually think of a
Speaker 2: process as the thing that's running, but it's actually more
Speaker 2: accurate to think of it as a management object, a container. Basically,
Speaker 2: I contain yeah, the actual work, the code execution that's
Speaker 2: done by threads within the process.
Speaker 1: Okay, So processes are like maybe office buildings, and threads
Speaker 1: are the workers inside.
Speaker 2: That's a great analogy. Exactly one can't really function without
Speaker 2: the other, but they definitely have distinct roles.
Speaker 1: Interesting, So if the process isn't the runner, what does
Speaker 1: it actually own what's inside this office building?
Speaker 2: Well, a process is responsible for some critical things. First,
Speaker 2: it gets its own private address space. Think of it
Speaker 2: like its own dedicated chunk of memory, its floor plan. Okay.
Speaker 2: Then it holds one or more threads, the workers. It
Speaker 2: also keeps a handle table.
Speaker 1: A handle table like an inventory list short of.
Speaker 2: Yeah, yeah, an inventory of all the system resources it's using.
Speaker 2: And critically, it's assigned a unique process ID.
Speaker 1: Or PID PIDs. Right, we see those in task Manager
Speaker 1: all the time. Now, the book says they're unique but
Speaker 1: also reusable. How does that work? I sort of assumed
Speaker 1: a PID was like permanent.
Speaker 2: Yeah, that's common thought. But the key thing is a
Speaker 2: PID uniquely identifies a currently running process.
Speaker 1: Ah only while it's active.
Speaker 2: Exactly as long as that kernel object representing the process exists,
Speaker 2: the PID is its tag. But once the process finishes,
Speaker 2: poof that kernel object is gone.
Speaker 1: And the number can be used again.
Speaker 2: Later, right for a completely different new process it's like
Speaker 2: reusing raffle ticket numbers for different draws.
Speaker 1: That makes total sense, and it's a good reminder. Then,
Speaker 1: when we see say multiple Chrome Windows Open or Word instances,
Speaker 1: each one is its own distinct process, with its own PID,
Speaker 1: its own resources, even though they all started from the
Speaker 1: same program file.
Speaker 2: Precisely, the dot exc file is the blueprint, but each
Speaker 2: running instance gets its own private stuff. Now about that
Speaker 2: address space, the private memory. Yeah, the book lays out
Speaker 2: some different sizes. It depends on whether it's a sixty
Speaker 2: four bit or a thirty two bit process.
Speaker 1: Right. For sixty four bit processes on sixty four bit Windows,
Speaker 1: we're talking massive amounts of space, right, like eight terabytes
Speaker 1: or even one hundred and twenty eight.
Speaker 2: Terrabyte, Yes, staggering numbers. Eight terabytes on Windows eight and earlier,
Speaker 2: and then one hundred and twenty eight terabytes from Windows
Speaker 2: eight point one onwards. It's like having an almost infinite
Speaker 2: address book.
Speaker 1: Okay, but what about those older thirty two bit programs,
Speaker 1: the one still running on our modern sixty four bit systems.
Speaker 2: Ah Okay, that's where it gets a bit more nuanced.
Speaker 2: By default, a thirty two bit process only gets a
Speaker 2: two gigabyte address.
Speaker 1: Space only two gigs.
Speaker 2: But if the program was built with a special flag,
Speaker 2: a setting called large address aware.
Speaker 1: Large address aware.
Speaker 2: Yeah, if it has that flag, it can actually access
Speaker 2: up to four gigabytes on a sixty four bit system.
Speaker 1: So it doubles its potential memory pretty much.
Speaker 2: Think of the flag as the thirty two bit program
Speaker 2: telling the sixty four bit system, Hey, I know how
Speaker 2: to handle more memory addresses than usual.
Speaker 1: Okay, so that flag signals it's ready for more space. Now.
Speaker 1: Another key piece here seems to be these dynamic link
Speaker 1: libraries DLLs.
Speaker 2: They're everywhere we really are. Dls are essentially packages. They
Speaker 2: contain codeta resources things a program might need, and they
Speaker 2: get loaded into a process dynamic or dynamically, meaning either
Speaker 2: when the process starts up that's called static linking even
Speaker 2: though it sounds contradictory, or later on when the process
Speaker 2: explicitly asks for it, which is true dynamic linking.
Speaker 1: The book mentions you can't just run a DLL directly,
Speaker 1: right because they don't have that main entry point like
Speaker 1: an executable.
Speaker 2: Correct, no main function. But the really interesting part and
Speaker 2: a big efficiency thing is the memory sharing.
Speaker 1: Ah, yes, tell me about that.
Speaker 2: So when multiple processes are using the same DLL, especially
Speaker 2: those common Windows DLLs in the system thirty two folder.
Speaker 1: Like kernel thirty two dot dll.
Speaker 2: Exactly or User thirty two dot DLL. The actual code
Speaker 2: from the DLL can be shared in physical.
Speaker 1: RAM, so you don't have multiple copies loaded, right.
Speaker 2: It avoids wasting precious RAM. It's a huge win.
Speaker 1: And these particular DLLs, the subsystem ones, they're the ones
Speaker 1: that actually implement the core Windows API. Aren't they the
Speaker 1: functions that applications call to talk to the OS.
Speaker 2: That's precisely it. They're the gateway for norm user mode
Speaker 2: applications to access the underlying power of the Windows kernel.
Speaker 2: And this focus is really what the book is all.
Speaker 1: About, which leads us nicely into the broader Windows architecture
Speaker 1: user mode versus kernel mode.
Speaker 2: User mode is where our everyday apps live, Notepad, your
Speaker 2: browser games, plus those subsystem DLLs we just talked about,
Speaker 2: and also something called win.
Speaker 1: RT and kernel mode is the deeper layer, the engine room.
Speaker 2: Correct, that's the privileged part of the OS where the
Speaker 2: core components run, managing hardware security, that kind of thing.
Speaker 1: So user processes, subsystem DLLs and win RT, what's.
Speaker 2: That win RT or Windows run Time is a newer
Speaker 2: API layer. It came in with Windows eight, mainly for
Speaker 2: those Universal Windows Platform apps UWP apps.
Speaker 1: The ones from the Microsoft Store mostly.
Speaker 2: Yeah, it's built on an older technology called comm Component
Speaker 2: Object Model, which is all about software components talking to
Speaker 2: each other. And win RT supports multiple programming languages.
Speaker 1: Interesting, and it's not just for UWP apps. No.
Speaker 2: Recently a subset of win rts is actually available for
Speaker 2: traditional desktop applications too. Seems like Microsoft is trying to
Speaker 2: bridge the gap between those two worlds.
Speaker 1: Makes sense now for anyone listening who's thinking about actually
Speaker 1: doing some Windows system programming. The book mentions Duols Visual
Speaker 1: Studio primarily.
Speaker 2: Yeah, Visual Studio is the main integrated development environment the ID.
Speaker 2: The book emphasizes just getting your development set up right
Speaker 2: from the start.
Speaker 1: And it mentions that even doing a basic Hello World
Speaker 1: application can teach you something.
Speaker 2: Absolutely. Just compiling it shows you the process and you
Speaker 2: might notice subtle differences depending on whether you build it
Speaker 2: for a thirty two bit system that's by eighty six
Speaker 2: or a sixty four bit system by sixty four.
Speaker 1: Okay, And following on from that, character encoding Unicode this
Speaker 1: sounds important.
Speaker 2: It's crucial, especially for software that needs to work globally.
Speaker 2: There's a Unicode setting usually set by default and visual
Speaker 2: studio when you.
Speaker 1: Compile, and that affects how strings are handled.
Speaker 2: Yes, yes, it determines whether a type like lpctstr in
Speaker 2: the code represents text using UTFS sixteen, which can handle
Speaker 2: pretty much any character from any language, or the much
Speaker 2: more limited ASCI standard.
Speaker 1: So UTS sixteen is generally preferred definitely, and.
Speaker 2: You see this directly in the Windows API functions themselves.
Speaker 2: A function like creep mutex, for example, isn't really one function. Well,
Speaker 2: it's like a macro. The compiler expands it to either
Speaker 2: create mutex WZ the WS for wide characters UTF sixteen,
Speaker 2: or create mutexa A for ANSI or ASCI ah.
Speaker 1: Okay, So using Unicode means you automatically get the w versions,
Speaker 1: which prevents your text getting garbled if it contains non
Speaker 1: English characters.
Speaker 2: Exactly. It voids data loss and makes your software work
Speaker 2: correctly with international text, absolutely vital these days.
Speaker 1: The book also flags safer ways to handle strings right
Speaker 1: like wccswise.
Speaker 2: Yes and functions from the struceay dot EA CHEDDAR. It's
Speaker 2: quick reminder that the old C style string functions can
Speaker 2: be risky, you know, buffer overflows and security issues. These
Speaker 2: newer functions are designed to be much safer.
Speaker 1: Good practice to use them and for the code example.
Speaker 1: In the book, it mentions helper libraries WISHL and WTL.
Speaker 2: Yeah, the Windows Implementation Library WIL and Windows Template Library WTL.
Speaker 2: They basically provide convenience C plus plus wrappers around the
Speaker 2: raw Windows API.
Speaker 1: Makes things less tedious pretty.
Speaker 2: Much save if you write in a lot of boilerplate code.
Speaker 2: Makes development quicker and less error prone. The book also
Speaker 2: touches on Hungarian notation.
Speaker 1: Oh yeah, that naming convention like hend for a window
Speaker 1: handle exactly.
Speaker 2: Or else dir for a pointer to a string. It's
Speaker 2: an older style you'll see in the Windows API documentation.
Speaker 2: In older code, it embeds the variable type.
Speaker 1: In the name, A bit of a historical thing. You
Speaker 1: don't have to use it in new code.
Speaker 2: No, not really, It's just good to recognize you when
Speaker 2: you see it. Okay, So moving on. No system programming
Speaker 2: discussion is complete without error handling. What happens when things
Speaker 2: go wrong?
Speaker 1: Right? How does the Windows API tell you something failed?
Speaker 2: There are a few common patterns you'll see. Functions return
Speaker 2: a bool. Generally, non zero means success es.
Speaker 1: Zero means failure, but don't check for exactly true.
Speaker 2: Right The book warms about that success might be one,
Speaker 2: or might be two or something else non zero, Just
Speaker 2: check if it's zero or not. Think you have types
Speaker 2: like l status or long. With those, zero usually means success.
Speaker 2: The constant error success is actually zero. Any positive value
Speaker 2: indicates a specific.
Speaker 1: Error code, an h result.
Speaker 2: A result is common two, especially with Calm and Newer
Speaker 2: APIs zero or positive generally means success as okay is
Speaker 2: zero and negative values signal different errors.
Speaker 1: So when a function does fail, how do you find
Speaker 1: out why?
Speaker 2: The main way is to immediately call to get last
Speaker 2: air function immediately Yes, because the next API call might
Speaker 2: overwrite the error code and critically get laster gives you
Speaker 2: the error code for the current thread.
Speaker 1: Ah, So each thread has its own last error value precisely.
Speaker 2: If you have multiple threads, you can assume one thread's
Speaker 2: error relates to another's failure. It's threads specific.
Speaker 1: Got it? Okay? What about finding out Windows version? The
Speaker 1: book says the old way get version X is kind
Speaker 1: of deprecated now.
Speaker 2: Yeah, it's not recommended for various reasons related to compatibility settings.
Speaker 2: The modern approach is better, which is there's a header
Speaker 2: file version all PRIs dot age with a bunch of
Speaker 2: simple functions like is Windows expra, greater, is Windows ten
Speaker 2: or greater is when a server and so on.
Speaker 1: They just return true or false.
Speaker 2: Exactly, much cleaner for most common version checks. Under the
Speaker 2: hood they use a more fundamental function called verify version info.
Speaker 2: Usually the helpers are all unique.
Speaker 1: Okay, nice and simple, right, let's ship gears. Objects and handles.
Speaker 1: These sound absolutely central to Windows.
Speaker 2: They are fundamental. Handles are everywhere. The book describes them
Speaker 2: as basically identifiers for kernel objects.
Speaker 1: Kernel objects being what kinds of things.
Speaker 2: These are the core resources managed by the Windows kernel itself,
Speaker 2: things like files you open, processes that are running threads
Speaker 2: doing work, synchronization tools like Mutex's events, all the basic building.
Speaker 1: Blocks, okay, And the handle is how our program.
Speaker 2: Refers to them, exactly. It's an abstract token, like a
Speaker 2: ticket or a claim check. Your user mode program uses
Speaker 2: the handle to tell the kernel which object it wants to.
Speaker 1: Interact with, so it provides a layer of abstraction and security.
Speaker 2: Yes, you don't get direct access to the kernel's internal
Speaker 2: data structures. You operate through the handle.
Speaker 1: So when we call say, create mutechs to make a
Speaker 1: synchronization object.
Speaker 2: If it works, you get back a handle value, a
Speaker 2: number basically that represents that mutex object living down in
Speaker 2: the kernel. And if it fails, the return values usually
Speaker 2: zero or null. And then there's open mutex, which is
Speaker 2: specifically for getting a handle to a mutex that already
Speaker 2: exists and has a name.
Speaker 1: Right. Create mutex is interesting because if you give it
Speaker 1: a name, it can either create a new named mutex
Speaker 1: or it can open an existing one with that name.
Speaker 2: How do you know what happened?
Speaker 1: Even if create mutex succeeds in opening an existing one,
Speaker 1: if you call get last ray after, it will return
Speaker 1: error already.
Speaker 2: Exists, ah okay, whereas open mutex just fails if the
Speaker 2: name mutex.
Speaker 1: Isn't there, correct, it won't create one for you.
Speaker 2: Now, the book breaks down what's sort of conceptually in
Speaker 2: a handle, A pointer to the object and access mask
Speaker 2: and flags.
Speaker 1: Yeah, that's a simplified view. The access mask is super important.
Speaker 1: It defines what operations you're actually allowed to perform using
Speaker 1: that specific handle, like permissions exactly. For instance, if you
Speaker 1: want to terminate another process. You first need a handle
Speaker 1: to it. You get that using open.
Speaker 2: Process, but when you call open process you have to
Speaker 2: explicitly request the process terminate access right. If the handle
Speaker 2: you get back doesn't have that right in its access mask,
Speaker 2: then calling terminate process with that handle will just fail.
Speaker 1: So the handle encodes the permissions. What about the flags
Speaker 1: inheritance Protection from close.
Speaker 2: Inheritance means whether a child process created by this process
Speaker 2: automatically gets a copy of the handle. Protection from close
Speaker 2: handle flag protects from close is a safety feature makes
Speaker 2: it harder to accidentally close a really important handle.
Speaker 1: Can you change these flags?
Speaker 2: Yes, using set handle information and get handle information. And
Speaker 2: if you really want to see all the handles a
Speaker 2: process has.
Speaker 1: Open process explorer.
Speaker 2: Process Explorer from cysinternals is the tool. It's invaluable. It
Speaker 2: shows the handle value, the type of object, file, thread,
Speaker 2: mutex its name if it has one, the object's address
Speaker 2: in kernel memory, the raw access mask, and even a
Speaker 2: decoded human readable version of the access rights like looking
Speaker 2: at the process's internal toolkit.
Speaker 1: Definitely a must have tool. Now, managing these handles in code,
Speaker 1: especially C plus plus plus A, seems error prone. The
Speaker 1: book introduces a smart handle wrapper class.
Speaker 2: Yes, it demonstrates a concept called r AII. R AI
Speaker 2: resource acquisition is initialization. It basically means the handle resource
Speaker 2: is acquired when the C plus plus wrapper object is created,
Speaker 2: and crucially, it's automatically released. The handle is closed when
Speaker 2: the wrapper object goes out of scope or is destroyed.
Speaker 1: Ah, so it cleans up after itself. Prevents handle leaks exactly.
Speaker 2: It makes handle management much safer and easier. The example
Speaker 2: class also prevents axidel copying of handles, but allows transferring
Speaker 2: ownership using something called move semantics. Very useful C plus
Speaker 2: plus features neat.
Speaker 1: Okay, What about object naming and sessions? Names aren't always
Speaker 1: global usually?
Speaker 2: Know when your regular user application creates a named object
Speaker 2: like a name mutex, that name is typically only visible
Speaker 2: within your current user login session.
Speaker 1: So another user logged in wouldn't see it.
Speaker 2: Correct unless you specifically create it in the global name space.
Speaker 1: How do you do that?
Speaker 2: You prefix the name with global like global mouse, shared, mutechs.
Speaker 2: These live in a special base named objects directory in
Speaker 2: the kernel's object manager name space.
Speaker 1: Can any application do this?
Speaker 2: Well, there's a catch. Modern sandbox apps called app containers
Speaker 2: usually don't have the permissions to create objects in the
Speaker 2: global name space. It's mainly for services or older desktop
Speaker 2: apps needing system wide coordination.
Speaker 1: So if you have two separate programs, maybe even started
Speaker 1: by different users, they could use these global named objects
Speaker 1: to communicate or synchronize.
Speaker 2: Yes, that's a primary use case. One process creates the
Speaker 2: named object, create mutex with the global name, and another
Speaker 2: process can open it using the same name, open mutext,
Speaker 2: or even create utechs. Again, the name acts is the
Speaker 2: rendezvous point.
Speaker 1: Interesting. Another mechanism mentioned is handle duplication using duplicate handle.
Speaker 1: What's that about?
Speaker 2: This lets you take a handle you have in your
Speaker 2: process and create a new handle, potentially in a different
Speaker 2: process that refers to the exact same underlying kernel object.
Speaker 1: Why would you do that?
Speaker 2: A common reason is when a parent process starts a
Speaker 2: child process, the parent might want to give the child
Speaker 2: access to one of its own open handles, like maybe
Speaker 2: it's standard input or output pipe, So.
Speaker 1: You duplicate the parent's handle into the child's process space.
Speaker 2: Exactly, you need a handle to the target process with
Speaker 2: the process you panel permission to do this. You can
Speaker 2: even duplicate a handle within the same process if you
Speaker 2: need another handle to the same objects, maybe with different
Speaker 2: access rights.
Speaker 1: Okay. The book then briefly mentions user objects Windows menus
Speaker 1: and GDI objects bitmaps, fonts. They're handled a bit differently.
Speaker 2: Yeah. User objects like Windows don't use reference counting in
Speaker 2: the same way kernel objects do. The first process to
Speaker 2: destroy one affects everyone sharing it and their handles their
Speaker 2: scope to something called a Windows station, which also manages
Speaker 2: things like the clipboard for applications on.
Speaker 1: The same desktop, and GDI objects.
Speaker 2: Managed by the GDI subsystem, a separate part of Windows.
Speaker 1: This is giving us a really solid grounding. Now the
Speaker 1: book starts talking about different types of processes. Protective processes
Speaker 1: light PPL sounds like a security thing.
Speaker 2: It is introduced in Windows eight point one. PPL provides
Speaker 2: enhanced protection, making these processes much harder to tamper with
Speaker 2: or terminate, even for administrators like antivirus software. That's a
Speaker 2: key example. Yes, anti malware services often run as PPLs
Speaker 2: to protect themselves from malicious software trying to shut them down.
Speaker 2: There are different protection levels within PPL.
Speaker 1: Then there are minimal processes Windows ten features. These sound
Speaker 1: really stripped down.
Speaker 2: They are. They start with a completely empty address space,
Speaker 2: no executable no DLLs initially mapped, super lightweight.
Speaker 1: What uses them?
Speaker 2: The registry process is one example. Another key one is
Speaker 2: the memory compression process, which works behind the scenes to
Speaker 2: optimize RAM usage.
Speaker 1: Memory compression I might not see that in task manager.
Speaker 2: Sometimes it is hidden or aggregated, but Process Explorer will
Speaker 2: definitely show it. These minimal processes are typically created directly
Speaker 2: by the kernel itself.
Speaker 1: Fascinating how processes are evolving. The book also clarifies that
Speaker 1: PIDs are just special handle values internally, and it covers
Speaker 1: the statuses running suspended and not responding. Not responding is
Speaker 1: just for GUI apps, right correct.
Speaker 2: It happens when the main UI thread gets stuck and
Speaker 2: doesn't process window messages for about five seconds or more.
Speaker 2: Command line apps never show not responding, okay.
Speaker 1: The book then mentions PE files portable executable, the format
Speaker 1: for dot exe and dot dll files, and how they
Speaker 1: list their dependencies the other DLLs they.
Speaker 2: Need right in the import table. And when you launch
Speaker 2: a program, the Windows loader has a specific search path
Speaker 2: that follows to find those needed DLLs.
Speaker 1: What's the order it checks known.
Speaker 2: DLLs first, special system ones, then the application's own directory,
Speaker 2: then the current directory, then the main system directory System
Speaker 2: thirty two or siswas sixty four, and finally all the
Speaker 2: directories in the system's path.
Speaker 1: Environment variable and if it can't find one, you get.
Speaker 2: That dreaded air message box and the process usually fails
Speaker 2: to start. Dependency loading is critical.
Speaker 1: Then we get to actually starting processes create process. Wow.
Speaker 1: Look at all those parameters.
Speaker 2: It's like the master control panel for launching applications. You
Speaker 2: specify the command line security settings, whether handles are inherited,
Speaker 2: creation flags.
Speaker 1: Creation flags like creating new console or create suspended exactly.
Speaker 2: Also the environment variables, the starting directory, the startup INNEFO
Speaker 2: structure which controls the window appearance, and you get back
Speaker 2: the handles and IDs in the process information structure. Huge
Speaker 2: amount of control.
Speaker 1: And process priority classes affecting thread priorities.
Speaker 2: Yes, ranging from idle up to real time. Most apps
Speaker 2: run at normal setting. Real time usually needs admin rights
Speaker 2: because it can really impact system responsiveness if misused.
Speaker 1: That startup infos structure too, controls window size position, whether
Speaker 1: it's shown, minimize, maximized, even redirecting standard input out pewter.
Speaker 2: It's how a parent process shapes the initial state of
Speaker 2: its child. The book also gives a nod to a
Speaker 2: useful visual studio extension for debugging child processes and reminds
Speaker 2: us again you can't just launch UWP apps like normal executables.
Speaker 1: Right, They need that special activation mechanism, which brings us
Speaker 1: back to PPL again briefly.
Speaker 2: Just reinforcing that they have different signer levels, restricting access
Speaker 2: even preventing termination by admins. You can see the protection
Speaker 2: level and process explorer. The book shows. Trying to launch
Speaker 2: calculator fails if you just copy its command line.
Speaker 1: Because it's a UWP app needs the proper.
Speaker 2: Launch exactly, which involves using those Windows run Time win
Speaker 2: rt API. As we mentioned, the I Application Activation Manager
Speaker 2: interface is key. Using methods like activate application, you often
Speaker 2: need the app's full package name.
Speaker 1: Okay. Then a quick mention of minimal and PICO processes. Again,
Speaker 1: minimal are kernel created. PICO processes are for things like
Speaker 1: the Windows subsystem for Linux WSL translating Linux calls.
Speaker 2: Right, but not the main focus here?
Speaker 1: Then, how processes end three ways? All threads exit exit
Speaker 1: processes call or termain it process from outside.
Speaker 2: Pretty much even when your main function returns. In CC
Speaker 2: plus plus two, the runtime library calls exit process from
Speaker 2: the kernel's view the process ends when its last thread terminates.
Speaker 1: And getting info about a running process, get exit code process,
Speaker 1: get process times for CPU usage.
Speaker 2: Query full process image name. To get the executable path,
Speaker 2: you need to allocate a buffer for that one.
Speaker 1: And listing all processes. The tool help thirty two snapshot functions.
Speaker 2: Create tool help thirty two snapshot process thirty two first,
Speaker 2: process thirty two next. That gives you the basics like
Speaker 2: PID in name for everything running.
Speaker 1: But to do more like terminate or get detailed info,
Speaker 1: you need open process first.
Speaker 2: Yes, and you need to request the right access permissions.
Speaker 2: It might fail for protected system processes. Air five is
Speaker 2: access denied. AIR eighty seven often means invalid parameter. Maybe
Speaker 2: the PID doesn't exist anymore.
Speaker 1: Debug privilege helps.
Speaker 2: Sometimes yes, it lets you open more processes running elevated
Speaker 2: and visual Studio often grants it implicitly. For even more detail,
Speaker 2: there's WTS enumerate process X.
Speaker 1: What does that give you things like.
Speaker 2: The username, session id, detailed CPU times, handle counts, threadcounts,
Speaker 2: or rich review.
Speaker 1: Okay, that's a lot on processes. Let's talk about jobs,
Speaker 1: grouping processes exactly.
Speaker 2: Job objects let you manage a set of processes as
Speaker 2: a single unit Process Explorer actually shows if a process
Speaker 2: is in a job, how do you use them? Create
Speaker 2: one with the separate job object, then add processes to
Speaker 2: it using assigned process to job object. You can even
Speaker 2: have hierarchies of jobs.
Speaker 1: But the real power is restrictions.
Speaker 2: Definitely. Using set information job object, you can set limits
Speaker 2: on the entire group of processes in the job, things
Speaker 2: like total CPU time, total memory commitment.
Speaker 1: You can limit UI interactions too, like blocking clipboard access.
Speaker 2: Yes, there are UI restrictions you can apply the book
Speaker 2: mentions a sample app job monitor that lets you play
Speaker 2: with this, like limiting notepad CPU or blocking certain actions.
Speaker 1: CPU rate control is newer Windows eight plus.
Speaker 2: Reret Right, let's you set a hard percentage limit on
Speaker 2: the CPU usage for all processes in the job combined.
Speaker 2: Very useful for resource management and sandboxing.
Speaker 1: Okay, super useful concept. Now let's dive into threads. We
Speaker 1: said these are the actual workers inside a process.
Speaker 2: Yes, the independent paths of execution. They allow a single
Speaker 2: process to do multiple things concurrently, potentially using multiple CPU cores.
Speaker 1: You create them with create thread. Need to give it
Speaker 1: a starting function, right.
Speaker 2: The threads entry point function plus an optional parameter to
Speaker 2: pass to it, stack size settings, creation flags like create
Speaker 2: suspended if you don't want to run immediately and you
Speaker 2: get back a handle and a thread ID.
Speaker 1: Tids are unique system wide like PIDs.
Speaker 2: Yes. The book also mentions HyperThreading as MT, where one
Speaker 2: physical core looks like multiple logical processors to the OS.
Speaker 1: Can boost performance, but potential cache issues can be.
Speaker 2: Yeah, threads on the same physical core might compete for cash.
Speaker 2: You see logical processors and task manager usually can disable
Speaker 2: SMT in the bios if needed.
Speaker 1: Now, terminating threads termat thread sounds.
Speaker 2: Bad, very bad. Generally it's abrupt. Kills the thread instantly
Speaker 2: without cleanup can lead to resource leaks, deadlocks, corrupted data.
Speaker 2: Much better to signal the thread to exit gracefully itself. Okay.
Speaker 1: Threads have stacks for local variables and handles like processes.
Speaker 1: You get one from create thread or open thread right.
Speaker 2: Open thread is like open process needs a TID in permissions. Interestingly,
Speaker 2: threads don't have a built in name property in the kernel.
Speaker 1: But there's a trick for debugging.
Speaker 2: Yeah. Using structured exceptions to set a pseudoname helps identify
Speaker 2: threads in the debugger, and.
Speaker 1: Choosing between c plus plus plus standard library threats and
Speaker 1: the Windows API.
Speaker 2: Standard librarystd dot thread et cetera. Is cross platform, which
Speaker 2: is great, but the Windows API Create thread gives you
Speaker 2: much finer control over things like priority, affinity, stack size,
Speaker 2: which leads us to scheduling.
Speaker 1: Right, How does Windows decide which thread runs when the
Speaker 1: scheduler and.
Speaker 2: The key thing. Most threads are usually waiting, waiting for IO,
Speaker 2: waiting for a lock, et cetera. The scheduler focuses on
Speaker 2: threads in the ready state. It's priority based.
Speaker 1: Higher priority runs first. Windows has levels from real time
Speaker 1: down to idle.
Speaker 2: Correct. A thread's actual priority comes from its processes priority
Speaker 2: class plus its own relative priority within that.
Speaker 1: Process and the quantum the time slice.
Speaker 2: Yeah, how long a thread gets to run before the
Speaker 2: scheduler might switch. Yeah, It can vary client versus server
Speaker 2: tuning and the four ground apps. Threads often get longer quantums.
Speaker 2: Quantum stretching for responsiveness.
Speaker 1: Can be tweaked in the registry WIN thirty two priority separation.
Speaker 2: It can. Yeah. You can also control which ars a
Speaker 2: thread runs on process or affinity set thread affinity mask
Speaker 2: is the basic way set thread group affinity for systems
Speaker 2: with sixty four.
Speaker 1: Processors and CPU sets a newer way to group processor Yes.
Speaker 2: Windows ten introduce them more abstract way to manage affinity
Speaker 2: using functions like set thread.
Speaker 1: THEEP sets now priority boosts. This sounds important for keeping
Speaker 1: things smooth.
Speaker 2: Very the system temporarily boosts a threads priority after certain
Speaker 2: events like IO completing or a window needing. Attention prevents
Speaker 2: the UI freezing.
Speaker 1: It decays back down afterwards.
Speaker 2: Yes, after the thread runs for a bit four ground
Speaker 2: threads get a bigger boost when they wake up from
Speaker 2: a weight. It's all about perceived responsiveness.
Speaker 1: Suspending and resuming threads. Suspend thread, ReSm thread Still a
Speaker 1: bad idea.
Speaker 2: Generally, Yes, very easy to cause deadlocks. Better to use
Speaker 2: proper signaling. There are also ways for threads to yield voluntarily.
Speaker 2: Sleep baze gives up the rest of its time slice
Speaker 2: to another ready thread of the same priority.
Speaker 1: Switch to thread yields more aggestively yes to any.
Speaker 2: Other ready thread, and sleep infinite just waits forever until
Speaker 2: woken up.
Speaker 1: It's amazing how much orchestration is going on. Okay, synchronization
Speaker 1: within a process. Why do we need it?
Speaker 2: Because if multiple threads in the same process access shared
Speaker 2: data without coordination, chaos, race conditions, corrupted data, weird bugs.
Speaker 1: The simple counter example shows this clearly.
Speaker 2: Yeah, the final count is unpredictable for simple increments decrements,
Speaker 2: there are interlock operations.
Speaker 1: Like interlocked increment. These are atomic, yes.
Speaker 2: Hardware guaranteed atomic. The whole read, modify write happens as
Speaker 2: one indivisible step, save for simple updates.
Speaker 1: For more complex stuff, protecting blocks of code.
Speaker 2: Critical sections of the workhorse for that, within a process
Speaker 2: initialized critical section X, enter critical section to lock it,
Speaker 2: leave critical section to unlock. Only one thread can be
Speaker 2: inside the critical section at a time, and delete critical
Speaker 2: section when done.
Speaker 1: Mutual exclusion. The hashcatch example uses one to protect.
Speaker 2: A map exactly std dot unordered map isn't thread safe,
Speaker 2: so the critic section ensures safe access from multiple threads.
Speaker 2: The book also mentions ETW event tracing.
Speaker 1: For Windows for diagnostics.
Speaker 2: Yeah, powerful kernel level tracing can see image loads, context switches,
Speaker 2: tons of stuff, useful for deep analysis.
Speaker 1: Okay, what about SRW locks slim reader.
Speaker 2: Writer These are often more efficient if you have lots
Speaker 2: of threads reading share data but only occasional rights. They
Speaker 2: allow multiple readers or one writer acquires RW lock shared
Speaker 2: acquires our wots exclusive, et cetera.
Speaker 1: Got it and condition variables used.
Speaker 2: With a lock always with a critical section or an
Speaker 2: SRW lock. They let threads wait efficiently for some condition
Speaker 2: to become true. You call sleep condition variable CS or
Speaker 2: sleep condition variable SRW.
Speaker 1: This atomically releases the lock while waiting yes.
Speaker 2: And reacquires it upon waking. Other threads use weight condition
Speaker 2: variable or wake all condition variable to signal crucially, you
Speaker 2: must recheck the condition in a loop after waking because
Speaker 2: of spurious wakeups.
Speaker 1: Spurious wakeups, they can and wake up even if the
Speaker 1: condition isn't met sometimes.
Speaker 2: Yes, so you always loop while sleep condition variable. The
Speaker 2: producer consumer example demonstrates this pattern well with a shared
Speaker 2: queue right.
Speaker 3: Newer primitives, too, wait and address very efficient way to
Speaker 3: wait for a specific memory location to change value, often
Speaker 3: without needing a separate lock and synchronization barriers like a
Speaker 3: Runov point exactly enter synchronization barrier. Threads wait there until
Speaker 3: a specified number of threads arrive. Then they all proceed
Speaker 3: together and C.
Speaker 1: Plus plus standard library has its own versions std dot
Speaker 1: mutex std dot condition variable Yes.
Speaker 2: Good for cross platform code, but often less control or
Speaker 2: potentially different performance characteristics than the native Windows APIs. Finally,
Speaker 2: the basic weight functions wait for single object, wait for multiple.
Speaker 1: Objects, need the synchronize right for the object.
Speaker 2: Handle yes, and you specify a timeout. They tell you
Speaker 2: if the objects signaled, if you kimbed out, or if
Speaker 2: there was an error.
Speaker 1: Okay, that covers coordinating threads inside one process. What about
Speaker 1: between different processes?
Speaker 2: For that, you need kernel objects with system wide visibility,
Speaker 2: usually achieved using named.
Speaker 1: Objects like a named mutex.
Speaker 2: Exactly create it with create viewtex and give it a name,
Speaker 2: maybe global prefix for system wide. Another process can use
Speaker 2: open mutex with the same name to get a handle
Speaker 2: to the same mutex. Then they use weight for single
Speaker 2: object and release mutechs to coordinate.
Speaker 1: Process Explorer can show these named mutexes.
Speaker 2: Yep and whether they're currently held. Semaphors work similarly.
Speaker 1: Somemophors control access to a limited number of resources.
Speaker 2: Right create with create semaphore, give it an initial max
Speaker 2: account and a name. Wait for single object, tries to
Speaker 2: decrement the count, release semaphor increments it. Good for managing
Speaker 2: pools of resources across processes.
Speaker 1: Weaightable timers can also be named yes.
Speaker 2: Create weightable timer with a name, set weightable timer to
Speaker 2: schedule it once or periodically. Other processes can open weightable
Speaker 2: timer and wait for single object. Can even trigger APCs
Speaker 2: and events.
Speaker 1: Named events also possible.
Speaker 2: Create event with a name, manual or auto reset, open
Speaker 2: event by name, use set event, reset event, wait for
Speaker 2: single object. Simple signaling between processes.
Speaker 1: Interprocess APCs are less common.
Speaker 2: Much less common and trickier named objects the usual way.
Speaker 2: The book also mentions weight for impuddle.
Speaker 1: Waits for a GUI app to be ready.
Speaker 2: Yeah waits until it's finished initializing and is waiting for input.
Speaker 2: Useful after create process and signal object and weight atomically
Speaker 2: signals one object and weights on another, avoiding certain race conditions.
Speaker 1: Lots of tools for interprocess coordination. Let's move to thread pools,
Speaker 1: a managed way to handle threads.
Speaker 2: Yeah, Windows provides a sophisticated threadpool big advantages, reuses threads,
Speaker 2: less overhead, manages resources, better limits concurrency automatically.
Speaker 1: What do you use it? Simplest way?
Speaker 2: Try submit threadpool callback, give it a function to run,
Speaker 2: and the pool schedules it on one of its worker
Speaker 2: threads eventually.
Speaker 1: That it can do more weight callbacks yes.
Speaker 2: Instead of blocking your own thread waiting for an object,
Speaker 2: tell the thread pool to weight, create threadpool weight, set
Speaker 2: thread pool weight. When the object signals, the pool runs
Speaker 2: your callback function. Much more efficient. Timer callbacks too, yep,
Speaker 2: create threadpool timer, set thread pool timer schedule callbacks ceriodically
Speaker 2: or one shot handled by the.
Speaker 1: Pool and io callbacks rising operations.
Speaker 2: Right to create thread poolio start thread Polio integrates acinc
Speaker 2: iiocompletion with the threadpool.
Speaker 1: Can you create your own private pools?
Speaker 2: You can create threadpool allows customization minmax threads, stack sizes,
Speaker 2: set threadpool thread maximum, et cetera. Need to close thread
Speaker 2: pool when done.
Speaker 1: Callback environments, cleanup groups.
Speaker 2: More advanced features environments, TP callback environ let you set priority, affinity, etc.
Speaker 2: For callbacks. Clean up groups help manage the lifetime of
Speaker 2: related pool objects. Together.
Speaker 1: Thread pools seem very powerful, okay. Advance threading topics. Thread
Speaker 1: local storage TLS.
Speaker 2: G LS gives each thread its own private coffee of
Speaker 2: some data. Use to get an index, then tlset value,
Speaker 2: TELS get value, operate on the calling threads specific slot
Speaker 2: for that index. No sink needed because it's thread private.
Speaker 2: TLS free releases the index.
Speaker 1: C plus plus s thread local two Yes t lous.
Speaker 2: Pec thread older and thread locals entered. C plus plus
Speaker 2: provide language level support for static TLS variables.
Speaker 1: How do list threads again, tool help thirty two YEP.
Speaker 2: Create tool help thirty two snapshot with th h three
Speaker 2: two CSS snap thread then thread thirty two first next
Speaker 2: gives TIDPID priority, CPU times.
Speaker 1: Cash awareness, False.
Speaker 2: Sharing important performance consideration. False sharing is when threads modified
Speaker 2: different variables that happen to be in the same CPU
Speaker 2: cache line, causing unnecessary cash and validations. Padding data structures
Speaker 2: can help avoid it.
Speaker 1: Weight change reversal WCT for.
Speaker 2: Dead's locks yes an API open thread weightchain, session get
Speaker 2: thread weight chain to analyze what locks and objects threads
Speaker 2: are waiting on. Can help diagnose deadlocks by showing circular weights.
Speaker 1: And the concurrency run time. High level C plus plus library.
Speaker 2: For Microsoft Ya provides tasks parallel loops agents simplifies many
Speaker 2: common parallel programming patterns.
Speaker 1: Okay, nearly there. File and device io Create file and
Speaker 1: create file two are key absolutely fundamental for opening creating files, devices, pipes,
Speaker 1: tons of parameters, path access rights, read write, share mode
Speaker 1: creation disposition like creating new open existing flags and attributes.
Speaker 2: File flag overlapped is crucial for ACNC io.
Speaker 1: Yes, and paths can include for devices or things like
Speaker 1: symbolic links. Drive letters themselves are often similark.
Speaker 2: Getting file info size.
Speaker 1: Attributes, get file size x sixty four bit size, get
Speaker 1: file attributesx, get file information by handle for more details,
Speaker 1: set file information by handle. Can even modify some things reading.
Speaker 2: And writing read file, write file, sync or async both.
Speaker 2: ACNC requires the file flag overlapped flag during create file
Speaker 2: and using an overlap structure. APCs are one way to
Speaker 2: handle ACNC completion, but iocompletion ports IOCP are more scalable.
Speaker 1: IOCP involves create iocompletion port associating hands than worker threads,
Speaker 1: calling get cubed completion status.
Speaker 2: Exactly highly efficient for servers handling many concurrent acinc io operations.
Speaker 2: Threadpool io create thread poolio is a simpler wrapper around
Speaker 2: similar concepts.
Speaker 1: Canceling IO, conciliox yes, cancilo.
Speaker 2: X for ACNC cancel synchronusio exist but isn't guaranteed to work.
Speaker 1: Device io uses create file with device paths like physical
Speaker 1: drive YEP.
Speaker 2: Then device iiO control since commands directly to the driver
Speaker 2: using control codes.
Speaker 1: Finding devices, the set up DAPI right.
Speaker 2: Set of digit class, DEEVS setup dynam device info. Setup
Speaker 2: DIET Device interface detail lets you find devices by type
Speaker 2: and get their paths.
Speaker 1: Interprocess communication again pipes anonymous and named.
Speaker 2: Create pipe for simple parent child anonymous pipes, create name
Speaker 2: pipe for more powerful. Name pipes can be duplex workover network.
Speaker 2: Clients connect using create.
Speaker 1: File mail slots one way.
Speaker 2: Yes, connectionless, create mail slot for server, Create fil rite
Speaker 2: file for client Yeah less common now also file finding
Speaker 2: find first file etcter and system info.
Speaker 1: Get system info okay, last major topic. Memory management fundamentals
Speaker 1: Virtual memory.
Speaker 2: The big abstraction. Each process gets its own private address
Speaker 2: s base managed by the virtual memory and manager. VMM
Speaker 2: uses paging to swap memory between RAM and the disc
Speaker 2: page file.
Speaker 1: Memory states free, reserved, committed, free is unused.
Speaker 2: Reserved allocates address range but no storage. Committed allocates storage
Speaker 2: RAM or page file commit, charge and task Manager is
Speaker 2: the system wide total committed.
Speaker 1: Memory for a process commits size, private bytes is key,
Speaker 1: working set is RAM usage generally.
Speaker 2: Yes, virtual size includes reserved, working set is physical. RAM.
Speaker 2: Process Explorer shows these well.
Speaker 1: Process memory map shows layout code, DLL stack keep, Get
Speaker 1: process memory info, gives detailed stats.
Speaker 2: Page faults working set size, pool usage, page file usage,
Speaker 2: and page protection. Read write execute is critical set by
Speaker 2: virtual ALC, change by virtual protect access violation if you break.
Speaker 1: The rules virtual virtual query X lets you walk the
Speaker 1: address space.
Speaker 2: Yes, gives in memory based information about regions, base size,
Speaker 2: state protection type. Let's you see the map programmatically.
Speaker 1: And finally, WAWW sixty four for running thirty two bit
Speaker 1: apps on sixty four bit Windows file system redirection system
Speaker 1: thirty two versus siswell sixty four.
Speaker 2: Exactly the emulation layer that makes it mostly seamless. Wow
Speaker 2: sixty four disabled whole sixty four f's redirection can turn
Speaker 2: off the file redirection temporarily if needed.
Speaker 1: Wow. Okay, that was genuinely a deep dive. We covered
Speaker 1: so much ground.
Speaker 2: We really did, from processes as containers, threads as the workers,
Speaker 2: through handles, synchronization nightmares huh.
Speaker 1: And io memory basics.
Speaker 2: It's a lot, it is. You know, one thing that
Speaker 2: always strikes me is that PID thing just being a
Speaker 2: handle value and those minimal processes completely empty to start with.
Speaker 2: That's pretty wild.
Speaker 1: Yeah. And the whole dance of threads scheduling the boosts.
Speaker 1: It really helps understand why things feel responsive for sometimes
Speaker 1: why they don't and for you listening, even if you're
Speaker 1: not writing this kind of low level code. I think
Speaker 1: understanding these concepts gives you a much better feel for
Speaker 1: what your computer is actually doing under the hood.
Speaker 2: It definitely demystifies some of it takes away the magic feeling.
Speaker 1: So thinking about all this complexity. It's what makes Windows powerful, right,
Speaker 1: but it also feels like there are so many moving parts.
Speaker 2: Absolutely, it's this incredible layering of abstractions and mechanisms built
Speaker 2: up over decades. It enables amazing things. But yeah, complexity
Speaker 2: can also mean fragility.
Speaker 1: Sometimes it makes you wonder how does this foundation contribute
Speaker 1: to both stability and the occasional crash, And what other
Speaker 1: deep system areas might be interesting to explore next time,
Speaker 1: maybe digging into how memory actually gets allocated or how
Speaker 1: drivers work.
Speaker 2: Definitely food for thought, something to mull over until our
Speaker 2: next deep dive. Thanks for joining us.