def run(self):
        ''' Use this funciton to get a Supervisor to run all tasks that it is
            managing. Execution occurs inside of a large loop with multiple
            steps. First, this supervisor checks all running tasks to see if
            they are finished. Those tasks that are finished are handled and
            removed from processing Next the Supervisor checks to see if any
            tasks can be started by checking their dependencies and making
            sure executing the task won't result in the SUpervisor exceeding
            the cpu_cap. Then, if force_run is False, the supervisor will
            check to see if the task can be skipped. If the task can be
            skipped, it will be, otherwise the task will be started. The loop
            breaks when their are no tasks left that can be executed and no
            tasks currently being executed.
        '''
        self.log_file = open(self.log_path, 'w', 1)
        self.last_email = time.time()
        self.tasks_to_run = set([t for t in self.tasks])
        self.tasks_running = set()
        cur_cpu = 0
        signal.signal(signal.SIGTERM, lambda *x: self.killRun())
        try:
            # execute run
            while(len(self.tasks_to_run) > 0 or len(self.tasks_running) > 0):
                size_tasks_to_run = len(self.tasks_to_run)
                # handling finished tasks
                for t in [task for task in self.tasks_running]:
                    temp = self.task_status[t]
                    try:
                        if(t.finished()):
                            self.tasks_running.remove(t)
                            cur_cpu -= t.cpu
                            temp['stop'] = int(time.time())
                            temp['state'] = Supervisor.STATE_FINISHED
                            temp['exit_code'] = t.exit_code
                            h, m, s = time_to_hms(temp['stop'] - temp['start'])
                            temp['message'] = 'Completed in {0!s}h {1!s}m {2!s}s'.format(h, m, s)
                            self.log(t.name+':'+self.task_status[t]['state']+':'+time.asctime()+'\n\n')
                    except (Task.ExitCodeException, Task.TaskException) as inst:
                        cur_cpu -= t.cpu
                        self.tasks_running.remove(t)
                        self.errors.append(inst)
                        temp['stop'] = int(time.time())
                        temp['state'] = Supervisor.STATE_ERR
                        temp['exit_code'] = t.exit_code
                        h, m, s = time_to_hms(temp['stop'] - temp['start'])
                        temp['message'] = 'Failed in {0!s}h {1!s}m {2!s}s'.format(h, m, s)
                        self.log(t.name+':'+self.task_status[t]['state']+':'+time.asctime()+'\n\n')
                        self.__removeTaskPath__(t)
                # starting execution of tasks
                for t in [task for task in self.tasks_to_run]:
                    temp = self.task_status[t]
                    if(t.cpu+cur_cpu > self.cpu):
                        continue
                    elif(not t.checkDependencies()):
                        continue
                    elif(not self.force_run and t.skipable()):
                        temp['state'] = Supervisor.STATE_SKIPPED
                        self.log(t.name+':'+temp['state']+'\n')
                        self.tasks_to_run.remove(t)
                        continue
                    else:
                        cur_cpu += t.cpu
                        self.tasks_running.add(t)
                        self.tasks_to_run.remove(t)
                        t.start()
                        temp['state'] = Supervisor.STATE_RUNNING
                        temp['start'] = int(time.time())
                        self.log(t.name+':'+self.task_status[t]['state']+':'+time.asctime()+'\n\n')
                        self.log_file.write(t.command+'\n\n')
                tasks_to_run_delta = size_tasks_to_run - len(self.tasks_to_run)
                if(len(self.tasks_running) == 0 and tasks_to_run_delta == 0):
                    break
                time.sleep(self.delay)
            # handle all errors
            if(self.errors != [] or (len(self.tasks_running) == 0 and len(self.tasks_to_run) != 0)):
                err_str = '\n\n'
                if(len(self.tasks_running) == 0 and len(self.tasks_to_run) != 0):
                    err_str += 'Unable to resolve dependencies during execution of '+self.name
                    err_str += '. The following tasks could not be executed:\n'
                    err_str += '\n'.join(['\t'+t.name for t in self.tasks_to_run])
                if(self.errors != []):
                    err_str += '\nEncountered an unexpected Error in the following tasks:\n'
                    for t in self.task_status:
                        if(self.task_status[t]['state'] == Supervisor.STATE_ERR):
                            err_str+= '\tName - {0!s} : Message - {1!s} : Exit Code - {2!s}\n'.format(
                                t.name,self.task_status[t]['message'],self.task_status[t]['exit_code'])
                    removed_tasks = []
                    for t in self.task_status:
                        if(self.task_status[t]['state']==Supervisor.STATE_REMOVED):
                            removed_tasks.append('\tName - {0!s} : Message - {1!s} : Exit Code- {2!s}\n'.format(
                                t.name,self.task_status[t]['message'],self.task_status[t]['exit_code']))
                    if(len(removed_tasks)>0):
                        err_str+='\nAs a result of the above errors, the following tasks could not be executed:\n'
                        err_str+=''.join(removed_tasks)
                    err_str+='\nErrors Reported:\n'
                    for e in self.errors:
                        err_str+=str(e)+'\n'
                raise Exception(err_str)            
        except BaseException as inst:
            self.killRun()
            self.log_file.write(str(inst))
            raise
        finally:
            self.send_email('', subject='MMT Finished')