The Pedigree Project  0.1
Process.cc
1 /*
2  * Copyright (c) 2008-2014, Pedigree Developers
3  *
4  * Please see the CONTRIB file in the root of the source tree for a full
5  * list of contributors.
6  *
7  * Permission to use, copy, modify, and distribute this software for any
8  * purpose with or without fee is hereby granted, provided that the above
9  * copyright notice and this permission notice appear in all copies.
10  *
11  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
18  */
19 
20 #if defined(THREADS)
21 
22 #include "pedigree/kernel/process/Process.h"
23 #include "modules/system/users/Group.h"
24 #include "modules/system/users/User.h"
25 #include "pedigree/kernel/Atomic.h"
26 #include "pedigree/kernel/LockGuard.h"
27 #include "pedigree/kernel/Log.h"
28 #include "pedigree/kernel/Spinlock.h"
29 #include "pedigree/kernel/Subsystem.h"
30 #include "pedigree/kernel/process/PerProcessorScheduler.h"
31 #include "pedigree/kernel/process/Scheduler.h"
32 #include "pedigree/kernel/process/Semaphore.h"
33 #include "pedigree/kernel/process/Thread.h"
34 #include "pedigree/kernel/processor/Processor.h"
35 #include "pedigree/kernel/processor/ProcessorInformation.h"
36 #include "pedigree/kernel/processor/VirtualAddressSpace.h"
37 #include "pedigree/kernel/processor/types.h"
38 #include "pedigree/kernel/time/Time.h"
39 #include "pedigree/kernel/utilities/Iterator.h"
40 #include "pedigree/kernel/utilities/List.h"
41 #include "pedigree/kernel/utilities/MemoryAllocator.h"
42 #include "pedigree/kernel/utilities/StaticString.h"
43 #include "pedigree/kernel/utilities/Vector.h"
44 #include "pedigree/kernel/utilities/ZombieQueue.h"
45 #include "pedigree/kernel/utilities/utility.h"
46 
48 
50  : m_Threads(), m_NextTid(0), m_Id(0), str(), m_pParent(0),
51  m_pAddressSpace(&VirtualAddressSpace::getKernelAddressSpace()),
52  m_ExitStatus(0), m_Cwd(0), m_Ctty(0), m_SpaceAllocator(false),
53  m_DynamicSpaceAllocator(false), m_pUser(0), m_pGroup(0),
54  m_pEffectiveUser(0), m_pEffectiveGroup(0), m_pDynamicLinker(0),
55  m_pSubsystem(0), m_Waiters(), m_bUnreportedSuspend(false),
56  m_bUnreportedResume(false), m_State(Active),
57  m_BeforeSuspendState(Thread::Ready), m_Lock(false), m_Metadata(),
58  m_LastKernelEntry(0), m_LastUserspaceEntry(0), m_pRootFile(0),
59  m_bSharedAddressSpace(false), m_DeadThreads(0)
60 {
61  resetCounts();
62  m_Metadata.startTime = Time::getTimeNanoseconds();
63 
66  getAddressSpace()->getUserStart(),
67  getAddressSpace()->getUserReservedStart() -
68  getAddressSpace()->getUserStart());
69  if (getAddressSpace()->getDynamicStart())
70  {
72  getAddressSpace()->getDynamicStart(),
73  getAddressSpace()->getDynamicEnd() -
74  getAddressSpace()->getDynamicStart());
75  }
76 }
77 
78 Process::Process(Process *pParent, bool bCopyOnWrite)
79  : m_Threads(), m_NextTid(0), m_Id(0), str(), m_pParent(pParent),
80  m_pAddressSpace(0), m_ExitStatus(0), m_Cwd(pParent->m_Cwd),
81  m_Ctty(pParent->m_Ctty), m_SpaceAllocator(pParent->m_SpaceAllocator),
83  m_pUser(pParent->m_pUser), m_pGroup(pParent->m_pGroup),
88  m_State(pParent->getState()), m_BeforeSuspendState(Thread::Ready),
89  m_Lock(false), m_Metadata(pParent->m_Metadata), m_LastKernelEntry(0),
91  m_bSharedAddressSpace(!bCopyOnWrite), m_DeadThreads(0)
92 {
93  m_pAddressSpace = pParent->m_pAddressSpace->clone(bCopyOnWrite);
94 
96 
97  // Set a temporary description.
98  str = m_pParent->str;
100  {
101  str += "<C>"; // C for cloned (i.e. shared address space)
102  }
103  else
104  {
105  str += "<F>"; // F for forked.
106  }
107 }
108 
110 {
111  // Make sure we have full mutual exclusion on the Subsystem before we lock
112  // here. This ensures we have full access to the subsystem and avoids a case
113  // where we lock here but the subsystem destruction needs to reschedule to
114  // acquire the subsystem locks.
115  if (m_pSubsystem)
116  {
118  }
119 
120  bool isSelf =
121  Processor::information().getCurrentThread()->getParent() == this;
122 
124  it != m_Threads.end(); ++it)
125  {
126  Thread *pThread = (*it);
127 
128  // Clean up thread if not actually us.
129  if (pThread != Processor::information().getCurrentThread())
130  {
131  // Child thread is not current thread - terminate the child
132  // properly.
133  pThread->setStatus(Thread::Zombie);
134  pThread->shutdown();
135  }
136  }
137 
138  // Block until we are the only one touching this Process object.
140 
141  // Guards things like removeThread.
142  m_State = Terminating;
143 
144  // Now that all threads are shut down and marked as zombies, and we have
145  // taken the main process Spinlock, we can clean up the detached threads.
147  it != m_Threads.end(); ++it)
148  {
149  Thread *t = (*it);
150  if (t != Processor::information().getCurrentThread())
151  {
152  if (t->detached())
153  {
154  delete t;
155  }
156  }
157  }
158 
160 
161  if (m_pSubsystem)
162  delete m_pSubsystem;
163 
164  VirtualAddressSpace &VAddressSpace =
165  Processor::information().getVirtualAddressSpace();
166 
167  bool bInterrupts = Processor::getInterrupts();
169 
172  Processor::switchAddressSpace(VAddressSpace);
173 
174  delete m_pAddressSpace;
175 
176  str.append("<Z>");
177 
178  Processor::setInterrupts(bInterrupts);
179 
180  if (isSelf)
181  {
182  // Killed current process, so kill off the thread too.
183  // NOTE: this DOES NOT RETURN. Anything critical to process shutdown
184  // must be completed by this point.
185  Processor::information().getScheduler().killCurrentThread(&m_Lock);
186  }
187 }
188 
189 size_t Process::addThread(Thread *pThread)
190 {
192  if (!pThread)
193  return ~0;
194  m_Threads.pushBack(pThread);
195  return m_NextTid += 1;
196 }
197 
199 {
200  // Don't bother in these states: already done, or is about to be done.
201  if (m_State == Terminating || m_State == Terminated)
202  return;
203 
206  it != m_Threads.end(); it++)
207  {
208  if (*it == pThread)
209  {
210  m_Threads.erase(it);
211  break;
212  }
213  }
214 
215  if (m_pSubsystem)
216  m_pSubsystem->threadRemoved(pThread);
217 }
218 
220 {
222  return m_Threads.count();
223 }
224 
226 {
228  if (n >= m_Threads.count())
229  {
230  m_Lock.release();
231  FATAL(
232  "Process::getThread(" << Dec << n << Hex
233  << ") - Parameter out of bounds.");
234  return 0;
235  }
236  return m_Threads[n];
237 }
238 
240 {
241  m_Lock.acquire();
242 
243 #ifdef VERBOSE_KERNEL
244  if (m_pParent)
245  NOTICE("Kill: " << m_Id << " (parent: " << m_pParent->getId() << ")");
246  else
247  NOTICE("Kill: " << m_Id << " (parent: <orphan>)");
248 #endif
249 
250  // Bye bye process - have we got any zombie children?
251  for (size_t i = 0; i < Scheduler::instance().getNumProcesses(); i++)
252  {
253  Process *pProcess = Scheduler::instance().getProcess(i);
254 
255  if (pProcess && (pProcess->m_pParent == this))
256  {
257  if (pProcess->getThread(0)->getStatus() == Thread::Zombie)
258  {
259  // Kill 'em all!
260  delete pProcess;
261  }
262  else
263  {
264  pProcess->m_pParent = Process::getInit();
265  }
266  }
267  }
268 
269  m_State = Terminated;
270 
272 
273  // Add to the zombie queue if the process is an orphan.
274  if (!m_pParent)
275  {
276  NOTICE(
277  "Process::kill() - process is an orphan, adding to ZombieQueue.");
278 
279  ZombieQueue::instance().addObject(new ZombieProcess(this));
280  Processor::information().getScheduler().killCurrentThread(&m_Lock);
281 
282  // Should never get here.
283  FATAL("Process: should never get here");
284  }
285 
286  // We'll get reaped elsewhere
287 #ifdef VERBOSE_KERNEL
288  NOTICE(
289  "Process::kill() - not adding to ZombieQueue, process has a parent.");
290 #endif
291  Processor::information().getScheduler().schedule(
292  Thread::Zombie, nullptr, &m_Lock);
293 
294  FATAL("Should never get here");
295 }
296 
298 {
299  m_bUnreportedSuspend = true;
300  m_ExitStatus = 0x7F;
301  m_BeforeSuspendState = m_Threads[0]->getStatus();
302  m_State = Suspended;
303  notifyWaiters();
304  // Notify parent that we're suspending.
305  if (m_pParent && m_pParent->getSubsystem())
306  m_pParent->getSubsystem()->threadException(
307  m_pParent->getThread(0), Subsystem::Child);
308  Processor::information().getScheduler().schedule(Thread::Suspended);
309 }
310 
312 {
313  m_bUnreportedResume = true;
314  m_ExitStatus = 0xFF;
315  m_State = Active;
316  notifyWaiters();
317  Processor::information().getScheduler().schedule(Thread::Ready);
318 }
319 
320 int64_t Process::getUserId() const
321 {
322  if (!getUser())
323  {
324  return -1;
325  }
326  return getUser()->getId();
327 }
328 
329 int64_t Process::getGroupId() const
330 {
331  if (!getGroup())
332  {
333  return -1;
334  }
335  return getGroup()->getId();
336 }
337 
338 int64_t Process::getEffectiveUserId() const
339 {
340  if (!getEffectiveUser())
341  {
342  return -1;
343  }
344  return getEffectiveUser()->getId();
345 }
346 
347 int64_t Process::getEffectiveGroupId() const
348 {
349  if (!getEffectiveGroup())
350  {
351  return -1;
352  }
353  return getEffectiveGroup()->getId();
354 }
355 
356 void Process::getSupplementalGroupIds(Vector<int64_t> &vec) const
357 {
358  // no-op
359 }
360 
361 void Process::addWaiter(Semaphore *pWaiter)
362 {
363  m_Waiters.pushBack(pWaiter);
364 }
365 
366 void Process::removeWaiter(Semaphore *pWaiter)
367 {
369  it != m_Waiters.end();)
370  {
371  if ((*it) == pWaiter)
372  {
373  it = m_Waiters.erase(it);
374  }
375  else
376  ++it;
377  }
378 }
379 
380 size_t Process::waiterCount() const
381 {
382  return m_Waiters.count();
383 }
384 
386 {
388  it != m_Waiters.end(); ++it)
389  {
390  (*it)->release();
391  }
392 }
393 
395 {
396  return m_pInitProcess;
397 }
398 
399 void Process::setInit(Process *pProcess)
400 {
401  if (m_pInitProcess)
402  {
403  return;
404  }
405  m_pInitProcess = pProcess;
406 }
407 
408 #endif // defined(THREADS)
void release()
Definition: Spinlock.cc:273
Group * getEffectiveGroup() const
Definition: Process.h:222
void pushBack(const T &value)
Definition: Vector.h:270
void pushBack(const T &value)
Definition: List.h:232
bool m_bUnreportedSuspend
Definition: Process.h:497
Spinlock m_Lock
Definition: Process.h:512
Iterator begin()
Definition: Vector.h:148
Iterator end()
Definition: Vector.h:160
virtual void processTerminated()
Definition: Process.h:430
void shutdown()
Definition: Thread.cc:234
size_t m_Id
Definition: Process.h:445
List< Semaphore * > m_Waiters
Definition: Process.h:494
static Process * getInit()
Definition: Process.cc:394
size_t count() const
Definition: Vector.h:264
static bool getInterrupts()
virtual void acquire()
Acquire full mutual exclusion for all Subsystem resources.
Definition: Subsystem.cc:25
size_t getId()
Definition: User.h:66
Iterator erase(Iterator &Iter)
Definition: List.h:343
Time::Timestamp m_LastKernelEntry
Definition: Process.h:546
ProcessState m_State
Definition: Process.h:503
size_t getId()
Definition: Process.h:108
File * m_pRootFile
Definition: Process.h:552
A vector / dynamic array.
bool m_bSharedAddressSpace
Definition: Process.h:555
File * m_Ctty
Definition: Process.h:469
void notifyWaiters()
Definition: Process.cc:385
virtual int64_t getUserId() const
Definition: Process.cc:320
Time::Timestamp startTime
Time at which process started.
Definition: Process.h:542
bool acquire(bool recurse=false, bool safe=true)
Definition: Spinlock.cc:43
MemoryAllocator m_DynamicSpaceAllocator
Definition: Process.h:477
virtual void threadException(Thread *pThread, ExceptionType eType)
Definition: Subsystem.cc:35
void free(T address, T length, bool merge=true)
Definition: RangeList.h:163
static ProcessorInformation & information()
Definition: Processor.cc:45
Subsystem * m_pSubsystem
Definition: Process.h:491
static void switchAddressSpace(VirtualAddressSpace &AddressSpace)
VirtualAddressSpace * m_pAddressSpace
Definition: Process.h:457
Time::Timestamp m_LastUserspaceEntry
Definition: Process.h:549
Group * m_pGroup
Definition: Process.h:481
Special wrapper object for Process.
Definition: ZombieQueue.h:36
void removeProcess(Process *pProcess)
Definition: Scheduler.cc:119
Vector< Thread * > m_Threads
Definition: Process.h:437
Atomic< size_t > m_NextTid
Definition: Process.h:441
Definition: List.h:64
File * m_Cwd
Definition: Process.h:465
Process()
Definition: Process.cc:49
MemoryAllocator & getDynamicSpaceAllocator()
Definition: Process.h:183
#define NOTICE(text)
Definition: Log.h:74
Definition: Log.h:136
Group * m_pEffectiveGroup
Definition: Process.h:485
size_t getNumProcesses()
Definition: Scheduler.cc:140
Iterator begin()
Definition: List.h:123
void resume()
Definition: Process.cc:311
static Scheduler & instance()
Definition: Scheduler.h:48
static Process * m_pInitProcess
Definition: Process.h:558
User * m_pEffectiveUser
Definition: Process.h:483
Group * getGroup() const
Definition: Process.h:211
Process * getProcess(size_t n)
Definition: Scheduler.cc:149
static void setInterrupts(bool bEnable)
void setStatus(Status s)
Definition: Thread.cc:364
size_t getNumThreads()
Definition: Process.cc:219
void suspend()
Definition: Process.cc:297
static void setInit(Process *pProcess)
Definition: Process.cc:399
User * getUser() const
Definition: Process.h:189
Thread * getThread(size_t n)
Definition: Process.cc:225
Status getStatus() const
Definition: Thread.h:192
virtual ~Process()
Definition: Process.cc:109
Definition: Thread.h:54
DynamicLinker * m_pDynamicLinker
Definition: Process.h:488
bool m_bUnreportedResume
Definition: Process.h:500
VirtualAddressSpace * getAddressSpace()
Definition: Process.h:120
size_t addProcess(Process *pProcess)
Definition: Scheduler.cc:109
LargeStaticString str
Definition: Process.h:449
MemoryAllocator m_SpaceAllocator
Definition: Process.h:473
virtual void revertToKernelAddressSpace()=0
Process * m_pParent
Definition: Process.h:453
Definition: Log.h:138
void kill() NORETURN
Definition: Process.cc:239
void removeThread(Thread *pThread)
Definition: Process.cc:198
size_t getId()
Definition: Group.h:51
#define FATAL(text)
Definition: Log.h:89
User * getEffectiveUser() const
Definition: Process.h:200
virtual VirtualAddressSpace * clone(bool copyOnWrite=true)=0
void erase(size_t index)
Definition: Vector.h:350
Iterator end()
Definition: List.h:135
int m_ExitStatus
Definition: Process.h:461
User * m_pUser
Definition: Process.h:479
Thread::Status m_BeforeSuspendState
Definition: Process.h:509
size_t addThread(Thread *pThread)
Definition: Process.cc:189
virtual void threadRemoved(Thread *pThread)
Definition: Subsystem.h:170
MemoryAllocator & getSpaceAllocator()
Definition: Process.h:178
bool detached() const
Definition: Thread.h:417
size_t count() const
Definition: List.h:227