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
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>
33 using namespace kernel
;
34 using kernel::virtual_memory
;
36 vector
<process
*> process::mProcessList
;
38 lightOS::spinlock
process::mListLock
;
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
,
51 process
*Process
= new process( name
,
54 ((flags
& lightOS::process::server
) != 0) ? true : false);
57 // Add the process to the list
60 mProcessList
.push_back(Process
);
65 // Create the initial thread
66 Process
->createThread( entryPoint
,
72 // TODO: use the event_manager
73 broadcastEvent( libkernel::event::create_process
,
77 return Process
->getId();
80 bool process::destroy(libkernel::process_id_t pid
)
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
);
94 // Destroy the process's ports
95 port_manager
&PortManager
= port_manager::instance();
96 PortManager
.destroy_process_ports(*Process
);
103 // TODO: Use the event_manager
104 broadcastEvent( libkernel::event::destroy_process
,
114 size_t process::size()
118 size_t size
= mProcessList
.size();
124 process
*process::get_process(libkernel::process_id_t id
)
128 process_iterator iEnd
= mProcessList
.end();
129 for (process_iterator i
= mProcessList
.begin();i
!= iEnd
;i
++)
130 if ((*i
)->getId() == id
)
140 process
*process::get_process_by_index(size_t index
)
144 process
*Process
= 0;
145 if (index
< mProcessList
.size())
146 Process
= mProcessList
[index
];
152 thread
*process::get_thread(libkernel::thread_id_t id
)
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
)
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
188 void process::registerEvent(libkernel::port_id_t port
,
189 libkernel::event type
,
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
)
206 void process::broadcastEvent( libkernel::event type
,
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
,
221 PortManager
.send(libkernel::message_port::kernel
, msg
);
224 process::process( const string
&cmdline
,
226 std::vector
<void*> pages
,
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
,
242 libkernel::thread_id_t tid
)
246 if (mFreeThreadStacks
.size() != 0)
248 stack
= mFreeThreadStacks
[mFreeThreadStacks
.size() - 1].first
;
249 stacksize
= mFreeThreadStacks
[mFreeThreadStacks
.size() - 1].second
;
250 mFreeThreadStacks
.pop_back();
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
);
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
);
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");
284 bool process::destroyThread(libkernel::thread_id_t id
)
286 if (mList
.size() == 1)
292 for (vector
<thread
*>::iterator i
=mList
.begin();i
!= mList
.end();i
++)
294 if ((*i
)->getId() == id
)
303 void process::destroyThread(thread
*Thread
)
305 mFreeThreadStacks
.push_back(Thread
->get_stack());
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
;
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
,
328 if (size
== 0)return 0;
331 page_allocator
&PageAllocator
= page_allocator::instance();
333 size_t pageCount
= size
/ virtual_memory::page_size
;
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
))
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;
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;
365 KERNEL_CONTEXT_START
;
366 for (size_t i
= 0;i
< Region
.size
;i
++)
369 if (Region
.continuous
== false)
370 address
= Region
.pages
[i
];
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
);
380 mRegions
.push_back(Region
);
381 result
= Region
.vAddress
;
385 LOG("process::create_memory_region(): Unknown memory region type");
391 Region
.size
= pageCount
;
392 Region
.vAddress
= mLatestMemoryRegion
;
393 Region
.physical
= true;
394 mLatestMemoryRegion
= adjust_pointer(mLatestMemoryRegion
, virtual_memory::page_size
* pageCount
);
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
),
406 mRegions
.push_back(Region
);
407 result
= Region
.vAddress
;
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
)
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
);
426 if ((*i
).physical
!= true)
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
);
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
]);
447 ERROR("process::free_memory_region(): region starting at 0x" << hex(reinterpret_cast<uintptr_t>(address
)) <<
450 void *process::allocate_shared_memory_region()
453 if (mFreeSharedMemory
.size() != 0)
455 address
= mFreeSharedMemory
.back();
456 mFreeSharedMemory
.pop_back();
460 address
= adjust_pointer(mLatestSharedMemory
, - virtual_memory::page_size
* 1024);
461 mLatestSharedMemory
= 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
;
476 State
.eip
= reinterpret_cast<uintptr_t>(mSignalHandler
);
478 context_handle_t ctx
= processor::context();
479 processor::context(mContext
.get_handle());
482 int *stack
= reinterpret_cast<int*>(State
.esp
);
486 processor::context(ctx
);
489 State
.rip
= reinterpret_cast<uintptr_t>(mSignalHandler
);
495 void process::signal_end()
497 thread
*Thread
= mList
[0];
498 thread_state
&State
= Thread
->get_cpu_state();
499 State
= mSignalState
;
503 // Delete all threads
504 for (vector
<thread
*>::iterator i
= mList
.begin();i
!= mList
.end();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
);
517 for (vector
<void*>::iterator i
= mPages
.begin();i
!= mPages
.end();i
++)
518 PageAllocator
.free(*i
);