4 ms·
Near pointers could exist in non-overlapping segments couldn't they? With 254KB you'd use 4 segments tops. There was some valid reason to have them overlap, but
by jojobas 2y ago
Near pointers could exist in non-overlapping segments couldn't they?
With 254KB you'd use 4 segments tops. There was some valid reason to have them overlap, but it quickly became obsolete.
- skissane 2y ago> There was some valid reason to have them overlap, but it quickly became obsolete. Under DOS, the (primary/initial) code segment acts as the PID. So overlapping segments enabled less memory fragmentation and more memory for child processes. If your program used less than 64 KB, then the part of 64KB it didn't use could be made available to child processes to use. Important in the early days, where some programs were structured as a main executable (which displayed the main menu), and then separate child executables for each menu item–the main menu executable would stay in memory while the child executable ran. (Overlays were more efficient, but also more complex for the developer.) People call DOS a "single-tasking" operating system, but that wasn't entirely true – processes could spawn child processes, it is just the main thread of the parent process was suspended while the child process ran, unless the child process turned into a TSR. Also, child processes could use interrupts–or even just CALL FAR (if you could get the target address somehow)–to make upcalls to APIs exported by their ancestors, which is a way ancestor processes could be reinvoked even while suspended. COMMAND.COM's INT 0x2E API is an example (something I wish Unix shells had–a child process can modify the parent shell's environment, by calling an API to make it run a built-in command). Not standard terminology, but personally I think it should be called "semi-multitasking". CP/M-80, by contrast, was a truly single-tasking operating system – only one process could fit in memory at a time, and instead of TSRs which were just normal processes which had returned to their parent without being removed from memory, you had RSXs which were a radically different type of thing from a normal program. (Normal programs are allocated at the bottom of memory, RSXs from the top down.) (Did CP/M-86, CP/M-68K, CP/M-8000, get closer to MS-DOS in this regard than CP/M-80 did? Obviously MP/M went further than mainstream MS-DOS ever did.)
- rep_lodsb 2y agoThis ability to load child processes and TSRs is mostly owed to the CPU architecture, not to the design of MS-DOS - CP/M-86 had it too. With a single flat address space, programs need to be either position independent (not possible at all on 8080), load at a fixed address, or include some type of relocation info. The DDT debugger in CP/M started with a "loader" which moved the rest of the code to the top of memory, aligned to a 256 byte "page" boundary. There was a bitmap of which bytes of the code referred to a page number (i.e. the high byte of an address), so those could be fixed up. With MP/M, every program had to be in such a format, minus the loader, which became part of the operating system. x86 memory segmentation is sort of a middle ground between that, and virtual address spaces for each process. No security of course, but at least some degree of isolation in case of bugs, and the convenience of having fixed addresses within each segment.
- skissane 2y ago> This ability to load child processes and TSRs is mostly owed to the CPU architecture, not to the design of MS-DOS - CP/M-86 had it too. Did CP/M-86 support child processes though? Also, did CP/M-86 support TSRs? I thought it supported RSXs which just like CP/M-80 were in a different format and manipulated by different APIs than normal programs, whereas under DOS any program can turn itself into a TSR at any time, you can't tell when you start it whether it is going to turn itself into one (unless you know what its code does, of course) Looking at https://www.seasip.info/Cpm/bdos.html#144 https://www.seasip.info/Cpm/bdos.html#144 I see BDOS function 144 (P_CREATE), for creating subprocesses, was implemented on MP/M and Concurrent CP/M – but I don't see any mention of it being implemented on (non-Concurrent) CP/M-86. CP/M-86 1.1 (but not 1.0) supported BDOS function 47 (P_CHAIN), for launching a new program – but like exec() on Unix, or the BASIC CHAIN statement, it terminated its caller before launching the new program. That said, PC-DOS/MS-DOS 1.x didn't really support subprocesses either. There was no documented API for creating them. The program loader was actually in COMMAND.COM, and while it called the DOS kernel to allocate memory for a new process (the undocumented API INT 0x21,0x26), COMMAND.COM was responsible for actually loading the .COM or .EXE from disk into the process' memory (including relocating .ees), so creating a child process required duplicating a large part of COMMAND.COM's code. In DOS 2.x, the image loader was moved into the DOS kernel, and a public API to spawn a child process (INT 0x21,0x4B) was added. COMMAND.COM also implemented its own API to start a child process (which would be a child of itself not the caller), INT 0x2E, but I don't believe that was there in DOS 1.x either. > With MP/M, every program had to be in such a format, minus the loader, which became part of the operating system. You are talking here about the CMD executable format?