def _line_tracer(self, frame, exc_info=False):
        """This function is called when debugger has decided that it must
        stop or break at this frame."""
        # next logging statement commented for performance
        _logger.f_debug("user_line() with " 
                        "threadName=%s, frame=%s, frame.f_code=%s, self.mainpyfile=%s,"
                        "self.should_break_here()=%s, self.should_stop_here()=%s\n",
                         threading.currentThread().name,
                         hex(id(frame)),
                         frame.f_code,
                         self.mainpyfile,
                         self.should_break_here(frame),
                         self.should_stop_here(frame))

        # next lines allow to focus debugging on only one thread
        if self.debugged_thread_ident is None:
            self.debugged_thread_ident = threading.currentThread().ident
            self.debugged_thread_name = threading.currentThread().name
        else:
            if threading.currentThread().ident != self.debugged_thread_ident:
                return

        # Acquire Breakpoint Lock before sending break command to remote client
        self._active_breakpoint_lock.acquire()
        self.status = 'stopped'
        frames = self.dump_frames(frame)
        exception=None
        warning_messages = []
        if exc_info:
            exception = {
                'type': IKPdbRepr(exc_info[1]),
                'info': exc_info[1].args[0]
            }

        if self.stop_at_first_statement:
            warning_messages = ["IKP3db stopped so that you can setup some "
                                "breakpoints before 'Resuming' execution."]
            self.stop_at_first_statement = False

        remote_client.send('programBreak', 
                           frames=frames,
                           threads= self.get_threads(),
                           result={'executionStatus': 'stopped'},  #=self.status
                           warning_messages=warning_messages,
                           exception=exception)
                           
        # Enter a loop to process commands sent by client
        while True:
            command = self._command_q.get()

            if command['cmd'] == 'resume':
                self.setup_resume()
                break
            
            elif command['cmd'] == 'stepOver':
                self.setup_step_over(frame)
                break
            
            elif command['cmd'] == 'stepInto':
                self.setup_step_into(frame)
                break
            
            elif command['cmd'] == 'stepOut':
                self.setup_step_out(frame)
                break
            
            elif command['cmd'] == 'evaluate':
                value, result_type = self.evaluate(command['frame'], 
                                                   command['expression'], 
                                                   command['global'], 
                                                   disable_break=command['disableBreak'])
                remote_client.reply(command['obj'], {'value': value, 'type': result_type})

            elif command['cmd'] == 'getProperties':
                error_messages = []
                if command.get('id', False):
                    po_value = ctypes.cast(command['id'], ctypes.py_object).value
                    result={'properties': self.extract_object_properties(po_value) or []}
                    command_exec_status = 'ok'
                else:
                    result={'properties': self.extract_object_properties(None) or []}
                    command_exec_status = 'ok'
                    
                _logger.e_debug("    => %s", result)
                remote_client.reply(command['obj'], result, 
                                    command_exec_status=command_exec_status,
                                    error_messages=error_messages)

            elif command['cmd'] == 'setVariable':
                error_messages = []
                result = {}
                command_exec_status = 'ok'
                # TODO: Rework to use id now that we are in right thread context
                err_message = self.let_variable(command['frame'], 
                                                command['name'], 
                                                command['value'])
                if err_message:
                    command_exec_status = 'error'
                    msg = "setVariable(%s=%s) failed with error: %s" % (command['name'], 
                                                                        command['value'],
                                                                        err_message)
                    error_messages = [msg]
                    _logger.e_error(msg)
                remote_client.reply(command['obj'], 
                                    result,
                                    command_exec_status=command_exec_status,
                                    error_messages=error_messages)
                                    
            elif command['cmd'] == '_InternalQuit':
                _logger.x_critical("Exiting tracer upon reception of _Internal"
                                   "Quit  command")
                raise IKPdbQuit()                                    

            else:
                _logger.x_critical("Unknown command: %s received by _line_tracer()" % resume_command)
                raise IKPdbQuit()

        self.status = 'running'
        self._active_breakpoint_lock.release()
        return
This function is called when debugger has decided that it must
        stop or break at this frame.