- kdevelop3 project files
[lightOS.git] / kernel / process.cpp
blobaa4aacb88227af683243739e3ad418c346711822
1 /*
2 lightOS kernel
3 Copyright (C) 2006-2009 Jörg Pfähler
5 This program is free software; you can redistribute it and/or
6 modify it under the terms of the GNU General Public License
7 as published by the Free Software Foundation; either version 2
8 of the License, or (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA
19 #include <algorithm>
20 #include <iterator>
21 #include <kernel/arch/arch.hpp>
22 #include <kernel/log.hpp>
23 #include <kernel/process.hpp>
24 #include <kernel/scheduler.hpp>
25 #include <kernel/port_manager.hpp>
26 #include <kernel/page_allocator.hpp>
27 #include <kernel/range_allocator.hpp>
28 #include <lightOS/c++utils.hpp>
29 #include <kernel/processor.hpp>
31 #include <kernel/virtual_memory.hpp>
32 using namespace std;
33 using namespace kernel;
34 using kernel::virtual_memory;
36 vector<process*> process::mProcessList;
37 #ifdef _LIGHTOS_SMP
38 lightOS::spinlock process::mListLock;
39 #endif
41 // TODO: Move to event_manager
42 vector<process::event> process::mEvents;
44 libkernel::process_id_t process::create( context &Context,
45 std::vector<void*> pages,
46 const std::string &name,
47 uintptr_t entryPoint,
48 size_t flags)
50 // Create the process
51 process *Process = new process( name,
52 Context,
53 pages,
54 ((flags & lightOS::process::server) != 0) ? true : false);
57 // Add the process to the list
58 LOCK(mListLock);
60 mProcessList.push_back(Process);
62 UNLOCK(mListLock);
65 // Create the initial thread
66 Process->createThread( entryPoint,
69 flags,
70 Process->getId());
72 // TODO: use the event_manager
73 broadcastEvent( libkernel::event::create_process,
74 Process->getId(),
75 0);
77 return Process->getId();
80 bool process::destroy(libkernel::process_id_t pid)
82 //LOCK(mListLock);
84 process_iterator iEnd = mProcessList.end();
85 for (process_iterator i = mProcessList.begin();i != iEnd;i++)
86 if ((*i)->getId() == pid)
88 // Remove the process from the list
89 process *Process = *i;
90 mProcessList.erase(i);
92 //UNLOCK(mLock);
94 // Destroy the process's ports
95 port_manager &PortManager = port_manager::instance();
96 PortManager.destroy_process_ports(*Process);
98 // Delete the process
99 KERNEL_CONTEXT_START;
100 delete Process;
101 KERNEL_CONTEXT_END;
103 // TODO: Use the event_manager
104 broadcastEvent( libkernel::event::destroy_process,
105 pid,
107 return true;
110 //UNLOCK(mListLock);
111 return false;
114 size_t process::size()
116 //LOCK(mListLock);
118 size_t size = mProcessList.size();
120 //UNLOCK(mListLock);
121 return size;
124 process *process::get_process(libkernel::process_id_t id)
126 //LOCK(mListLock);
128 process_iterator iEnd = mProcessList.end();
129 for (process_iterator i = mProcessList.begin();i != iEnd;i++)
130 if ((*i)->getId() == id)
132 //UNLOCK(mLock);
133 return *i;
136 //UNLOCK(mListLock);
137 return 0;
140 process *process::get_process_by_index(size_t index)
142 //LOCK(mListLock);
144 process *Process = 0;
145 if (index < mProcessList.size())
146 Process = mProcessList[index];
148 //UNLOCK(mListLock);
149 return Process;
152 thread *process::get_thread(libkernel::thread_id_t id)
154 //LOCK(mListLock);
156 process_iterator iEnd = mProcessList.end();
157 for (process_iterator i = mProcessList.begin();i != iEnd;i++)
158 for (vector<thread*>::iterator y=(*i)->mList.begin();y != (*i)->mList.end();y++)
159 if ((*y)->getId() == id)
161 UNLOCK(mListLock);
162 return *y;
165 //UNLOCK(mListLock);
166 return 0;
170 // TODO TODO TODO TODO TODO TODO TODO TODO
173 size_t process::used_page_count() const
175 // text/data/heap size in pages
176 size_t pagecount = mPages.size();
178 // Add thread stack sizes
179 for (vector<thread*>::iterator i = mList.begin();i != mList.end();i++)
181 pair<void*,size_t> threadStack = (*i)->get_stack();
182 pagecount += threadStack.second / virtual_memory::page_size;
185 // TODO: Add memory regions
186 return pagecount;
188 void process::registerEvent(libkernel::port_id_t port,
189 libkernel::event type,
190 size_t param1,
191 size_t param2)
193 event Event = {port, type, param1, param2};
194 mEvents.push_back(Event);
196 void process::unregisterEvent( libkernel::port_id_t port,
197 libkernel::event type)
199 for (vector<event>::iterator i=mEvents.begin();i != mEvents.end();i++)
200 if ((*i).port == port && (*i).type == type)
202 mEvents.erase(i);
203 return;
206 void process::broadcastEvent( libkernel::event type,
207 size_t param1,
208 size_t param2)
210 for (vector<event>::iterator i=mEvents.begin();i != mEvents.end();i++)
211 if ((*i).type == type &&
212 ((*i).param1 == 0 || (*i).param1 == param1) &&
213 ((*i).param2 == 0 || (*i).param2 == param2))
215 port_manager &PortManager = port_manager::instance();
216 libkernel::message_t msg((*i).port,
217 libkernel::message::event,
218 type,
219 param1,
220 param2);
221 PortManager.send(libkernel::message_port::kernel, msg);
224 process::process( const string &cmdline,
225 context &Context,
226 std::vector<void*> pages,
227 bool isServer)
228 : mIsServer(isServer), mCmdLine(cmdline), mContext(Context), mPid(generateId()),
229 mLatestThreadStack(THREAD_STACK_START), mPages(pages), mLatestSharedMemory(SHARED_MEMORY_START),
230 mLatestMemoryRegion(MEMORY_REGION_START), mSignalHandler(0)
232 for (size_t i = 1;i < 5;i++)
234 mStandardPorts[i] = i;
235 mStandardFsPorts[i] = i;
238 libkernel::thread_id_t process::createThread( uintptr_t entryPoint,
239 size_t param1,
240 size_t param2,
241 size_t flags,
242 libkernel::thread_id_t tid)
244 void *stack;
245 size_t stacksize;
246 if (mFreeThreadStacks.size() != 0)
248 stack = mFreeThreadStacks[mFreeThreadStacks.size() - 1].first;
249 stacksize = mFreeThreadStacks[mFreeThreadStacks.size() - 1].second;
250 mFreeThreadStacks.pop_back();
252 else
254 stack = mLatestThreadStack;
255 mLatestThreadStack = adjust_pointer(mLatestThreadStack, - 1024 * 1024);
257 page_allocator &PageAllocator = page_allocator::instance();
258 void *page = PageAllocator.allocate();
259 mPages.push_back(page);
260 mContext.map( page,
261 adjust_pointer(stack, - virtual_memory::page_size),
262 lightOS::context::write | lightOS::context::user);
263 stacksize = virtual_memory::page_size;
266 thread *Thread = new thread(*this, entryPoint, stack, stacksize, param1, param2, tid);
267 mList.push_back(Thread);
268 if ((flags & lightOS::thread::suspended) != 0)
270 Thread->block(thread::suspended);
272 else
274 scheduler::add(Thread);
277 libkernel::thread_id_t ThreadID = Thread->getId();
278 if (port_manager::instance().create(*this, ThreadID) == false)
280 ERROR("process::create(): Could not create the thread port");
282 return ThreadID;
284 bool process::destroyThread(libkernel::thread_id_t id)
286 if (mList.size() == 1)
288 destroy(mPid);
289 return true;
292 for (vector<thread*>::iterator i=mList.begin();i != mList.end();i++)
294 if ((*i)->getId() == id)
296 destroyThread(*i);
297 mList.erase(i);
298 return true;
301 return false;
303 void process::destroyThread(thread *Thread)
305 mFreeThreadStacks.push_back(Thread->get_stack());
306 delete Thread;
308 void *process::heapAlloc(size_t count)
310 return mContext.heap_map(count, lightOS::context::write | lightOS::context::user, this);
312 bool process::set_standard_port(libkernel::port_id_t stdPort, libkernel::port_id_t Port, libkernel::port_id_t fsPort)
314 if (stdPort >= 5 || stdPort == 0)return false;
315 mStandardPorts[stdPort] = Port;
316 mStandardFsPorts[stdPort] = fsPort;
317 return true;
319 pair<libkernel::port_id_t,libkernel::port_id_t> process::get_standard_port(libkernel::port_id_t stdPort)
321 if (stdPort >= 5 || stdPort == 0)return pair<libkernel::port_id_t,libkernel::port_id_t>(0, 0);
322 return pair<libkernel::port_id_t, libkernel::port_id_t>(mStandardPorts[stdPort], mStandardFsPorts[stdPort]);
324 void *process::create_memory_region(size_t size,
325 size_t flags,
326 void *physical)
328 if (size == 0)return 0;
330 void *result = 0;
331 page_allocator &PageAllocator = page_allocator::instance();
333 size_t pageCount = size / virtual_memory::page_size;
335 if (physical == 0)
337 if ((size % virtual_memory::page_size) != 0)++pageCount;
338 if ((flags & lightOS::memory::type_mask) == lightOS::memory::below_1mb ||
339 (flags & lightOS::memory::type_mask) == lightOS::memory::below_16mb ||
340 ((flags & lightOS::memory::type_mask) == lightOS::memory::below_4gb && pageCount == 1) ||
341 ((flags & lightOS::memory::type_mask) == lightOS::memory::below_4gb && (flags & lightOS::memory::continuous) != lightOS::memory::continuous))
343 region Region;
344 Region.size = pageCount;
345 Region.vAddress = mLatestMemoryRegion;
346 Region.physical = false;
347 mLatestMemoryRegion = adjust_pointer(mLatestMemoryRegion, virtual_memory::page_size * pageCount);
348 if ((flags & lightOS::memory::type_mask) == lightOS::memory::below_1mb ||
349 (flags & lightOS::memory::type_mask) == lightOS::memory::below_16mb)
351 // Allocate memory below 1/16MB (NOTE: always continuous)
352 range_allocator &RangeAllocator = range_allocator::instance();
353 Region.pages.push_back(RangeAllocator.allocate_range(pageCount, flags & lightOS::memory::type_mask));
354 Region.continuous = true;
356 else
358 // Allocate memory below 4GB (NOTE: never continuous)
359 for (size_t i=0;i < pageCount;i++)
360 Region.pages.push_back(PageAllocator.allocate());
361 Region.continuous = false;
364 // Map the pages
365 KERNEL_CONTEXT_START;
366 for (size_t i = 0;i < Region.size;i++)
368 void *address;
369 if (Region.continuous == false)
370 address = Region.pages[i];
371 else
372 address = adjust_pointer(Region.pages[0], virtual_memory::page_size * i);
374 mContext.map( address,
375 adjust_pointer(Region.vAddress, virtual_memory::page_size * i),
376 lightOS::context::write | lightOS::context::user);
378 KERNEL_CONTEXT_END;
380 mRegions.push_back(Region);
381 result = Region.vAddress;
383 else
385 LOG("process::create_memory_region(): Unknown memory region type");
388 else
390 region Region;
391 Region.size = pageCount;
392 Region.vAddress = mLatestMemoryRegion;
393 Region.physical = true;
394 mLatestMemoryRegion = adjust_pointer(mLatestMemoryRegion, virtual_memory::page_size * pageCount);
396 // Map the pages
397 KERNEL_CONTEXT_START;
398 for (size_t i = 0;i < Region.size;i++)
400 mContext.map( adjust_pointer(physical, virtual_memory::page_size * i),
401 adjust_pointer(Region.vAddress, virtual_memory::page_size * i),
402 flags);
404 KERNEL_CONTEXT_END;
406 mRegions.push_back(Region);
407 result = Region.vAddress;
409 return result;
411 void process::free_memory_region(void *address)
413 vector<region>::iterator i = mRegions.begin();
414 for (;i != mRegions.end();i++)
415 if ((*i).vAddress == address)
417 // Unmap the region
418 KERNEL_CONTEXT_START;
419 for (size_t y = 0;y < (*i).size;y++)
421 void *address = adjust_pointer((*i).vAddress, y * virtual_memory::page_size);
422 mContext.unmap(address);
424 KERNEL_CONTEXT_END;
426 if ((*i).physical != true)
428 // Free the region
429 if (reinterpret_cast<uintptr_t>((*i).pages[0]) < 0x1000000)
431 // NOTE: This is always continuous
432 range_allocator &RangeAllocator = range_allocator::instance();
433 RangeAllocator.free_range(reinterpret_cast<uintptr_t>((*i).pages[0]), (*i).size);
435 else
437 // NOTE: This is never continuous
438 page_allocator &PageAllocator = page_allocator::instance();
439 for (size_t y = 0;y < (*i).size;y++)
440 PageAllocator.free((*i).pages[y]);
444 mRegions.erase(i);
445 return;
447 ERROR("process::free_memory_region(): region starting at 0x" << hex(reinterpret_cast<uintptr_t>(address)) <<
448 " not found");
450 void *process::allocate_shared_memory_region()
452 void *address = 0;
453 if (mFreeSharedMemory.size() != 0)
455 address = mFreeSharedMemory.back();
456 mFreeSharedMemory.pop_back();
458 else
460 address = adjust_pointer(mLatestSharedMemory, - virtual_memory::page_size * 1024);
461 mLatestSharedMemory = address;
463 return address;
465 void process::free_shared_memory_region(void *address)
467 mFreeSharedMemory.push_back(address);
469 bool process::signal(size_t sig)
471 thread *Thread = mList[0];
472 thread_state &State = Thread->get_cpu_state();
473 mSignalState = State;
475 #ifdef X86
476 State.eip = reinterpret_cast<uintptr_t>(mSignalHandler);
478 context_handle_t ctx = processor::context();
479 processor::context(mContext.get_handle());
481 State.esp -= 4;
482 int *stack = reinterpret_cast<int*>(State.esp);
483 *stack = sig;
484 State.esp -= 4;
486 processor::context(ctx);
487 #endif
488 #ifdef X86_64
489 State.rip = reinterpret_cast<uintptr_t>(mSignalHandler);
490 State.rdi = sig;
491 #endif
493 return true;
495 void process::signal_end()
497 thread *Thread = mList[0];
498 thread_state &State = Thread->get_cpu_state();
499 State = mSignalState;
501 process::~process()
503 // Delete all threads
504 for (vector<thread*>::iterator i = mList.begin();i != mList.end();i++)
506 destroyThread(*i);
509 // Free the process regions
510 page_allocator &PageAllocator = page_allocator::instance();
511 while (mRegions.size() != 0)
513 free_memory_region(mRegions[0].vAddress);
516 // Free all pages
517 for (vector<void*>::iterator i = mPages.begin();i != mPages.end();i++)
518 PageAllocator.free(*i);