User Segments
Every segment in an x86 system is identified by an index into one of two tables: the local descriptor table (LDT) or the global descriptor table (GDT). One of these tables is for the process, and the other is for the operating system.
The idea was that the OS would use the GDT to define segments for things like handling system calls, which were shared among all processes. Each process would then be able to define up to 8192 segments of its own. Some operating systems, as well as code written in PL/M, often make good use of this capability.
For example, each thread in a C program might have one segment for the stack and one segment for thread-local storage. This approach presented a problem with older versions of Linux, which also used a segment for mapping files and a segment for the heap, with enough left for just over 4,000 threads. When this number was exceeded, you couldn't create any more.
The important thing about the LDT, in spite of its limitations, was that it exposed some of the power of the virtual memory system to the userspace programmer. The lack of equivalent functionality is a serious problem in modern systems. Consider something like a Flash or JavaScript vulnerability in a modern browser. The browser is trying to behave like a simple OS, isolating the different web pages from each other and from the rest of the system, but it doesn't have all of the tools at its disposal that the OS has. It can't simply use the CPU's features to isolate one sub-process from anotherit must try to do this entirely in software. A simple bug means that the untrusted code can escape the sandbox.
Unfortunately, due to other limitations in the segmentation system, this potential was never realized.