':param subdir: name of the group
:param testname: name of the test to run, or support step
:function: subroutine to run
:param args: arguments for the function
:returns: the result of the passed in function'

def _rungroup(self, subdir, testname, function, timeout, *args, **dargs):

    try:
        optional_fields = None
        if timeout:
            optional_fields = {'timeout': timeout}
        self.record('START', subdir, testname, optional_fields=optional_fields)
        self._state.set('client', 'unexpected_reboot', (subdir, testname))
        try:
            result = function(*args, **dargs)
            self.record('END    GOOD', subdir, testname)
            return result
        except error.TestBaseException as e:
            self.record(('END    %s' % e.exit_status), subdir, testname)
            raise
        except error.JobError as e:
            self.record('END    ABORT', subdir, testname)
            raise
        except Exception as e:
            err_msg = ((str(e) + '\n') + traceback.format_exc())
            self.record('END    ERROR', subdir, testname, err_msg)
            raise
    finally:
        self._state.discard('client', 'unexpected_reboot')
