Added multiple threads per process
This commit is contained in:
parent
f3b1bfc5ef
commit
b00f6d6217
@ -27,3 +27,5 @@ syscall_hdlr_0(uint32_t, getCurrentTerminalWidth, "21");
|
|||||||
syscall_hdlr_0(uint32_t, getCurrentTerminalHeight, "22");
|
syscall_hdlr_0(uint32_t, getCurrentTerminalHeight, "22");
|
||||||
|
|
||||||
syscall_hdlr_1(uint32_t, getProcessState, "23", uint32_t, PID);
|
syscall_hdlr_1(uint32_t, getProcessState, "23", uint32_t, PID);
|
||||||
|
|
||||||
|
syscall_hdlr_1(void, spawnThread, "24", uint32_t, functionPointer);
|
@ -4,6 +4,7 @@ namespace Global {
|
|||||||
Allocator* allocator = 0;
|
Allocator* allocator = 0;
|
||||||
Kernel* kernel = 0;
|
Kernel* kernel = 0;
|
||||||
Process* currentProc = 0;
|
Process* currentProc = 0;
|
||||||
|
Thread* currentThread = 0;
|
||||||
tss_struct* tss = 0;
|
tss_struct* tss = 0;
|
||||||
bool currentProcValid = false;
|
bool currentProcValid = false;
|
||||||
uint32_t milliseconds_elapsed = 0;
|
uint32_t milliseconds_elapsed = 0;
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
class Kernel;
|
class Kernel;
|
||||||
class Allocator;
|
class Allocator;
|
||||||
class Process;
|
class Process;
|
||||||
|
class Thread;
|
||||||
struct tss_struct;
|
struct tss_struct;
|
||||||
class ReadWriter;
|
class ReadWriter;
|
||||||
|
|
||||||
@ -13,6 +14,7 @@ namespace Global {
|
|||||||
extern Allocator* allocator;
|
extern Allocator* allocator;
|
||||||
extern Kernel* kernel;
|
extern Kernel* kernel;
|
||||||
extern Process* currentProc;
|
extern Process* currentProc;
|
||||||
|
extern Thread* currentThread;
|
||||||
extern tss_struct* tss;
|
extern tss_struct* tss;
|
||||||
extern bool currentProcValid;
|
extern bool currentProcValid;
|
||||||
extern uint32_t milliseconds_elapsed;
|
extern uint32_t milliseconds_elapsed;
|
||||||
|
@ -84,15 +84,15 @@ void context_switch(frame_struct* frame) {
|
|||||||
|
|
||||||
asm ("cli"); // Disable interrupts whilst handling the context switch.
|
asm ("cli"); // Disable interrupts whilst handling the context switch.
|
||||||
|
|
||||||
xnoe::linkedlist<Process*>* processes = &Global::kernel->processes;
|
xnoe::linkedlist<Thread*>* threads = &Global::kernel->threads;
|
||||||
|
|
||||||
if (!processes->start) {
|
if (!threads->start) {
|
||||||
Global::kernel->terminal->printf("[FATAL] No more processes! Halting!\n");
|
Global::kernel->terminal->printf("[FATAL] No more processes! Halting!\n");
|
||||||
while (1) asm ("hlt");
|
while (1) asm ("hlt");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Global::currentProcValid)
|
if (Global::currentProcValid)
|
||||||
Global::currentProc->kernelStackPtr = frame->new_esp;
|
Global::currentThread->kernelStackPtr = frame->new_esp;
|
||||||
|
|
||||||
// This cursed bit of code first determines if the processes list is longer than 1 and if it is
|
// This cursed bit of code first determines if the processes list is longer than 1 and if it is
|
||||||
// - Determines if it has 2 or more elements
|
// - Determines if it has 2 or more elements
|
||||||
@ -100,40 +100,41 @@ void context_switch(frame_struct* frame) {
|
|||||||
// - If it has more than two, add the start to the end then set start to the second element
|
// - If it has more than two, add the start to the end then set start to the second element
|
||||||
uint32_t count = 0;
|
uint32_t count = 0;
|
||||||
do {
|
do {
|
||||||
if (count++ == processes->length)
|
if (count++ == threads->length)
|
||||||
return;
|
return;
|
||||||
if (Global::currentProc) {
|
if (Global::currentThread) {
|
||||||
if (processes->start->next != 0) {
|
if (threads->start->next != 0) {
|
||||||
if (processes->end->prev == processes->start) {
|
if (threads->end->prev == threads->start) {
|
||||||
xnoe::linkedlistelem<Process*>* tmp = processes->start;
|
xnoe::linkedlistelem<Thread*>* tmp = threads->start;
|
||||||
processes->start = processes->end;
|
threads->start = threads->end;
|
||||||
processes->end = tmp;
|
threads->end = tmp;
|
||||||
|
|
||||||
processes->start->prev = 0;
|
threads->start->prev = 0;
|
||||||
processes->end->next = 0;
|
threads->end->next = 0;
|
||||||
processes->end->prev = processes->start;
|
threads->end->prev = threads->start;
|
||||||
processes->start->next = processes->end;
|
threads->start->next = threads->end;
|
||||||
} else {
|
} else {
|
||||||
processes->end->next = processes->start;
|
threads->end->next = threads->start;
|
||||||
processes->start = processes->start->next;
|
threads->start = threads->start->next;
|
||||||
processes->start->prev = 0;
|
threads->start->prev = 0;
|
||||||
xnoe::linkedlistelem<Process*>* tmp = processes->end;
|
xnoe::linkedlistelem<Thread*>* tmp = threads->end;
|
||||||
processes->end = processes->end->next;
|
threads->end = threads->end->next;
|
||||||
processes->end->next = 0;
|
threads->end->next = 0;
|
||||||
processes->end->prev = tmp;
|
threads->end->prev = tmp;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Global::currentProc = processes->start->elem;
|
Global::currentThread = threads->start->elem;
|
||||||
} while (Global::currentProc->state != Running);
|
Global::currentProc = threads->start->elem->parent;
|
||||||
|
} while (Global::currentThread->state != Running);
|
||||||
|
|
||||||
|
|
||||||
// Select the next processes page directory
|
// Select the next processes page directory
|
||||||
frame->new_cr3 = Global::currentProc->PD->phys_addr;
|
frame->new_cr3 = Global::currentThread->parent->PD->phys_addr;
|
||||||
// Restore kernelStackPtr of the new process.
|
// Restore kernelStackPtr of the new process.
|
||||||
frame->new_esp = Global::currentProc->kernelStackPtr;
|
frame->new_esp = Global::currentThread->kernelStackPtr;
|
||||||
|
|
||||||
Global::tss->esp0 = Global::currentProc->kernelStackPtrDefault;
|
Global::tss->esp0 = Global::currentThread->kernelStackPtrDefault;
|
||||||
|
|
||||||
// Set the current proc to valid
|
// Set the current proc to valid
|
||||||
Global::currentProcValid = true;
|
Global::currentProcValid = true;
|
||||||
@ -171,8 +172,8 @@ namespace Timer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void awaken(frame_struct* frame, Process* p) {
|
void awaken(frame_struct* frame, Thread* t) {
|
||||||
p->state = Running;
|
t->state = Running;
|
||||||
}
|
}
|
||||||
|
|
||||||
void syscall(frame_struct* frame) {
|
void syscall(frame_struct* frame) {
|
||||||
@ -351,8 +352,8 @@ void syscall(frame_struct* frame) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
case 18: { // sleep
|
case 18: { // sleep
|
||||||
Global::currentProc->state = Suspended;
|
Global::currentThread->state = Suspended;
|
||||||
Timer::register_event(frame->ebx, &awaken, (void*)Global::currentProc, true);
|
Timer::register_event(frame->ebx, &awaken, (void*)Global::currentThread, true);
|
||||||
context_switch(frame);
|
context_switch(frame);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -375,11 +376,18 @@ void syscall(frame_struct* frame) {
|
|||||||
xnoe::maybe<Process*> p = Global::kernel->pid_map->get(frame->ebx);
|
xnoe::maybe<Process*> p = Global::kernel->pid_map->get(frame->ebx);
|
||||||
if (p.is_ok()) {
|
if (p.is_ok()) {
|
||||||
Process* proc = p.get();
|
Process* proc = p.get();
|
||||||
rval = proc->state;
|
//rval = proc->state;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case 24: { // Spawn Thread
|
||||||
|
Thread* thread = new Thread(Global::currentProc);
|
||||||
|
thread->initKernelStack(frame->ebx, thread->stack);
|
||||||
|
Global::kernel->threads.append(thread);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -25,7 +25,7 @@ Process* Kernel::createProcess(ReadWriter* file) {
|
|||||||
this->pid_map->set(currentPID, p);
|
this->pid_map->set(currentPID, p);
|
||||||
currentPID++;
|
currentPID++;
|
||||||
|
|
||||||
this->processes.append(p);
|
this->threads.append(p->threads.start->elem);
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
@ -39,7 +39,11 @@ Process* Kernel::createProcess(ReadWriter* file, ReadWriter* stdout) {
|
|||||||
void Kernel::destroyProcess(Process* p) {
|
void Kernel::destroyProcess(Process* p) {
|
||||||
if (Global::currentProc == p)
|
if (Global::currentProc == p)
|
||||||
Global::currentProcValid = false;
|
Global::currentProcValid = false;
|
||||||
this->processes.remove(p);
|
xnoe::linkedlistelem<Thread*>* currentThread = p->threads.start;
|
||||||
|
while (currentThread) {
|
||||||
|
this->threads.remove(currentThread->elem);
|
||||||
|
currentThread = currentThread->next;
|
||||||
|
}
|
||||||
this->pid_map->remove(p->PID);
|
this->pid_map->remove(p->PID);
|
||||||
delete p;
|
delete p;
|
||||||
}
|
}
|
||||||
|
@ -21,8 +21,6 @@ Process::Process(uint32_t PID, void* stack, PageDirectory* page_directory, PageM
|
|||||||
this->PID = PID;
|
this->PID = PID;
|
||||||
this->page_remaining = 0;
|
this->page_remaining = 0;
|
||||||
this->last_page_pointer = virt_alloc_base;
|
this->last_page_pointer = virt_alloc_base;
|
||||||
this->stack = stack;
|
|
||||||
this->state = Running;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Process::Process(uint32_t PID)
|
Process::Process(uint32_t PID)
|
||||||
@ -30,9 +28,6 @@ Process::Process(uint32_t PID)
|
|||||||
this->PID = PID;
|
this->PID = PID;
|
||||||
this->page_remaining = 0;
|
this->page_remaining = 0;
|
||||||
this->last_page_pointer = 0;
|
this->last_page_pointer = 0;
|
||||||
this->stack = this->allocate(0x8000);
|
|
||||||
this->kernelStackPtr = (new uint8_t[0x4000]) + 0x4000;
|
|
||||||
this->state = Running;
|
|
||||||
this->file_handlers = new xnoe::dynarray<ReadWriter*>(8);
|
this->file_handlers = new xnoe::dynarray<ReadWriter*>(8);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -41,12 +36,9 @@ Process::Process(uint32_t PID, PageDirectory* inherit, uint32_t inheritBase, Rea
|
|||||||
this->stdout = 0;
|
this->stdout = 0;
|
||||||
this->stdin = 0;
|
this->stdin = 0;
|
||||||
|
|
||||||
this->firstRun = true;
|
|
||||||
|
|
||||||
this->PID = PID;
|
this->PID = PID;
|
||||||
this->page_remaining = 0;
|
this->page_remaining = 0;
|
||||||
this->last_page_pointer = 0;
|
this->last_page_pointer = 0;
|
||||||
this->state = Running;
|
|
||||||
|
|
||||||
this->file_handlers = new xnoe::dynarray<ReadWriter*>(8);
|
this->file_handlers = new xnoe::dynarray<ReadWriter*>(8);
|
||||||
|
|
||||||
@ -56,17 +48,14 @@ Process::Process(uint32_t PID, PageDirectory* inherit, uint32_t inheritBase, Rea
|
|||||||
uint32_t filesize = filereader->size();
|
uint32_t filesize = filereader->size();
|
||||||
uint8_t* program_data = this->allocate(filesize + 12) + 12;
|
uint8_t* program_data = this->allocate(filesize + 12) + 12;
|
||||||
|
|
||||||
uint8_t* argenvarea = this->allocate(0x2000);
|
Thread* thread = new Thread(this);
|
||||||
|
|
||||||
this->stack = this->allocate(0x8000);
|
|
||||||
this->kernelStackPtr = (new uint8_t[0x4000]) + 0x4000;
|
|
||||||
this->kernelStackPtrDefault = this->kernelStackPtr;
|
|
||||||
|
|
||||||
uint32_t pCR3;
|
uint32_t pCR3;
|
||||||
asm ("mov %%cr3, %0" : "=a" (pCR3) :);
|
asm ("mov %%cr3, %0" : "=a" (pCR3) :);
|
||||||
this->PD->select();
|
this->PD->select();
|
||||||
|
|
||||||
uint32_t* stack = this->stack + 0x8000;
|
uint32_t* stack = thread->stack + 0x8000;
|
||||||
|
uint8_t* argenvarea = this->allocate(0x2000);
|
||||||
uint32_t argenv = argenvarea + 0x2000;
|
uint32_t argenv = argenvarea + 0x2000;
|
||||||
for (int i=argc; i>0; i--) {
|
for (int i=argc; i>0; i--) {
|
||||||
char* s = argv[i-1];
|
char* s = argv[i-1];
|
||||||
@ -79,14 +68,39 @@ Process::Process(uint32_t PID, PageDirectory* inherit, uint32_t inheritBase, Rea
|
|||||||
|
|
||||||
*(--stack) = argc;
|
*(--stack) = argc;
|
||||||
|
|
||||||
// We also need to initialise ESP and the stack
|
filereader->seek(0);
|
||||||
|
filereader->read(filesize, program_data);
|
||||||
|
|
||||||
|
asm ("mov %0, %%cr3" : : "r" (pCR3));
|
||||||
|
|
||||||
|
thread->initKernelStack(program_data, stack);
|
||||||
|
|
||||||
|
this->threads.append(thread);
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread::Thread(Process* parent) {
|
||||||
|
this->parent = parent;
|
||||||
|
|
||||||
|
this->stack = this->parent->allocate(0x8000);
|
||||||
|
this->kernelStackPtr = (new uint8_t[0x4000]) + 0x4000;
|
||||||
|
this->kernelStackPtrDefault = this->kernelStackPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
Thread::~Thread() {
|
||||||
|
delete kernelStackPtr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Thread::initKernelStack(void* entryPoint, void* esp) {
|
||||||
|
uint32_t pCR3;
|
||||||
|
asm ("mov %%cr3, %0" : "=a" (pCR3) :);
|
||||||
|
this->parent->PD->select();
|
||||||
uint32_t* stack32 = ((uint32_t)this->kernelStackPtr);
|
uint32_t* stack32 = ((uint32_t)this->kernelStackPtr);
|
||||||
*(--stack32) = 0x23; // SS
|
*(--stack32) = 0x23; // SS
|
||||||
*(--stack32) = ((uint32_t)stack); // ESP
|
*(--stack32) = ((uint32_t)esp); // ESP
|
||||||
*(--stack32) = 0x200; // EFLAGS
|
*(--stack32) = 0x200; // EFLAGS
|
||||||
*(--stack32) = 27; // CS
|
*(--stack32) = 27; // CS
|
||||||
*(--stack32) = (uint32_t)program_data; // EIP
|
*(--stack32) = (uint32_t)entryPoint; // EIP
|
||||||
*(--stack32) = ((uint32_t)stack); // EBP
|
*(--stack32) = ((uint32_t)esp); // EBP
|
||||||
|
|
||||||
uint32_t rEBP = stack32;
|
uint32_t rEBP = stack32;
|
||||||
|
|
||||||
@ -100,10 +114,6 @@ Process::Process(uint32_t PID, PageDirectory* inherit, uint32_t inheritBase, Rea
|
|||||||
*(--stack32) = 0; // EDI
|
*(--stack32) = 0; // EDI
|
||||||
|
|
||||||
this->kernelStackPtr = stack32;
|
this->kernelStackPtr = stack32;
|
||||||
|
|
||||||
filereader->seek(0);
|
|
||||||
filereader->read(filesize, program_data);
|
|
||||||
|
|
||||||
asm ("mov %0, %%cr3" : : "r" (pCR3));
|
asm ("mov %0, %%cr3" : : "r" (pCR3));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -127,7 +137,11 @@ Process::~Process() {
|
|||||||
delete r.get();
|
delete r.get();
|
||||||
}
|
}
|
||||||
|
|
||||||
delete kernelStackPtr;
|
xnoe::linkedlistelem<Thread*>* currentThread = threads.start;
|
||||||
|
while (currentThread) {
|
||||||
|
delete currentThread->elem;
|
||||||
|
currentThread = currentThread->next;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void* Process::allocate(uint32_t size) {
|
void* Process::allocate(uint32_t size) {
|
||||||
|
@ -12,6 +12,22 @@
|
|||||||
#include "datatypes/dynarray.h"
|
#include "datatypes/dynarray.h"
|
||||||
#include "filesystem/fstree.h"
|
#include "filesystem/fstree.h"
|
||||||
|
|
||||||
|
class Process;
|
||||||
|
class Thread {
|
||||||
|
public:
|
||||||
|
void* stack;
|
||||||
|
void* kernelStackPtr;
|
||||||
|
void* kernelStackPtrDefault;
|
||||||
|
Process* parent;
|
||||||
|
ProcessState state;
|
||||||
|
bool firstRun;
|
||||||
|
|
||||||
|
Thread(Process* parent);
|
||||||
|
~Thread();
|
||||||
|
|
||||||
|
void Thread::initKernelStack(void* entryPoint, void* esp);
|
||||||
|
};
|
||||||
|
|
||||||
struct AllocTracker {
|
struct AllocTracker {
|
||||||
void* page_base;
|
void* page_base;
|
||||||
uint32_t page_size;
|
uint32_t page_size;
|
||||||
@ -25,8 +41,6 @@ private:
|
|||||||
uint32_t last_page_pointer;
|
uint32_t last_page_pointer;
|
||||||
uint32_t page_remaining;
|
uint32_t page_remaining;
|
||||||
|
|
||||||
void* stack;
|
|
||||||
|
|
||||||
// List of pages this process has allocated
|
// List of pages this process has allocated
|
||||||
xnoe::linkedlist<AllocTracker> allocations;
|
xnoe::linkedlist<AllocTracker> allocations;
|
||||||
|
|
||||||
@ -40,15 +54,10 @@ public:
|
|||||||
uint32_t PID;
|
uint32_t PID;
|
||||||
uint32_t esp;
|
uint32_t esp;
|
||||||
|
|
||||||
void* kernelStackPtr;
|
|
||||||
void* kernelStackPtrDefault;
|
|
||||||
|
|
||||||
ReadWriter* stdout;
|
ReadWriter* stdout;
|
||||||
ReadWriter* stdin;
|
ReadWriter* stdin;
|
||||||
|
|
||||||
bool firstRun;
|
xnoe::linkedlist<Thread*> threads;
|
||||||
|
|
||||||
ProcessState state;
|
|
||||||
|
|
||||||
Process(uint32_t PID, void* stack, PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint32_t virt_alloc_base);
|
Process(uint32_t PID, void* stack, PageDirectory* page_directory, PageMap* phys, PageMap* virt, uint32_t virt_alloc_base);
|
||||||
Process(uint32_t PID);
|
Process(uint32_t PID);
|
||||||
|
@ -151,11 +151,38 @@ bool strcmpcnt(int count, char* a, char* b) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
procbuffer b1;
|
||||||
|
procbuffer b2;
|
||||||
|
|
||||||
|
int bufferWidth;
|
||||||
|
|
||||||
|
void displayBuffer1() {
|
||||||
|
char c[128];
|
||||||
|
int succ=0;
|
||||||
|
while (1) {
|
||||||
|
if (b1.process)
|
||||||
|
if (succ = read(128, b1.stdout, c))
|
||||||
|
writeCountToBuf(succ, c, &b1);
|
||||||
|
displayBuf(&b1, 2, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void displayBuffer2() {
|
||||||
|
char c[128];
|
||||||
|
int succ=0;
|
||||||
|
while (1) {
|
||||||
|
if (b2.process)
|
||||||
|
if (succ = read(128, b2.stdout, c))
|
||||||
|
writeCountToBuf(succ, c, &b2);
|
||||||
|
displayBuf(&b2, bufferWidth+4, 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
int width = getCurrentTerminalWidth();
|
int width = getCurrentTerminalWidth();
|
||||||
int height = getCurrentTerminalHeight();
|
int height = getCurrentTerminalHeight();
|
||||||
|
|
||||||
int bufferWidth = (width - 4) / 2;
|
bufferWidth = (width - 4) / 2;
|
||||||
int bufferHeight = (height - 4);
|
int bufferHeight = (height - 4);
|
||||||
|
|
||||||
bindToKeyboard();
|
bindToKeyboard();
|
||||||
@ -201,7 +228,7 @@ int main() {
|
|||||||
uint32_t p2in = bindStdin(p2);
|
uint32_t p2in = bindStdin(p2);
|
||||||
fclose(program);
|
fclose(program);
|
||||||
|
|
||||||
procbuffer b1 = {
|
b1 = (procbuffer) {
|
||||||
.buffer = malloc(bufferWidth * bufferHeight),
|
.buffer = malloc(bufferWidth * bufferHeight),
|
||||||
.x = 0,
|
.x = 0,
|
||||||
.y = 0,
|
.y = 0,
|
||||||
@ -212,7 +239,7 @@ int main() {
|
|||||||
.height = bufferHeight
|
.height = bufferHeight
|
||||||
};
|
};
|
||||||
|
|
||||||
procbuffer b2 = {
|
b2 = (procbuffer) {
|
||||||
.buffer = malloc(bufferWidth * bufferHeight),
|
.buffer = malloc(bufferWidth * bufferHeight),
|
||||||
.x = 0,
|
.x = 0,
|
||||||
.y = 0,
|
.y = 0,
|
||||||
@ -223,6 +250,9 @@ int main() {
|
|||||||
.height = bufferHeight
|
.height = bufferHeight
|
||||||
};
|
};
|
||||||
|
|
||||||
|
spawnThread(&displayBuffer1);
|
||||||
|
spawnThread(&displayBuffer2);
|
||||||
|
|
||||||
procbuffer* selectedBuf = &b1;
|
procbuffer* selectedBuf = &b1;
|
||||||
|
|
||||||
writeStrToBuf("XoSH (XOS SHell) v0.0.1\nPress : to use commands.\n :help for help.\n", &b1);
|
writeStrToBuf("XoSH (XOS SHell) v0.0.1\nPress : to use commands.\n :help for help.\n", &b1);
|
||||||
@ -230,9 +260,6 @@ int main() {
|
|||||||
while (1) {
|
while (1) {
|
||||||
char c[128];
|
char c[128];
|
||||||
int succ = 0;
|
int succ = 0;
|
||||||
if (b1.process)
|
|
||||||
if (succ = read(128, b1.stdout, c))
|
|
||||||
writeCountToBuf(succ, c, &b1);
|
|
||||||
if (b2.process)
|
if (b2.process)
|
||||||
if (succ = read(128, b2.stdout, c))
|
if (succ = read(128, b2.stdout, c))
|
||||||
writeCountToBuf(succ, c, &b2);
|
writeCountToBuf(succ, c, &b2);
|
||||||
@ -309,8 +336,5 @@ int main() {
|
|||||||
write(1, selectedBuf->stdin, c);
|
write(1, selectedBuf->stdin, c);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
displayBuf(&b1, 2, 2);
|
|
||||||
displayBuf(&b2, bufferWidth+4, 2);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
Loading…
x
Reference in New Issue
Block a user