view libgui/graphics/ObjectProxy.cc @ 28347:00a9a49c7670 stable

improve interpreter shutdown process (bug #56952) This change is a further attempt to avoid segfaults when shutting down the interpreter and exiting the GUI event loop. The latest approach is to have the interpreter signal that it is finished with "normal" command execution (REPL, command line script, or --eval option code), then let the GUI thread process any remaining functions in its event loop(s) then signal back to the interpreter that it is OK to shutdown. Once the shutdown has happened (which may involve further calls to the GUI thread while executing atexit functions or finish.m or other shutdown code, the interpreter signals back to the GUI that shutdown is complete. At that point, the GUI can delete the interpreter object and exit. * ObjectProxy.h, ObjectProxy.cc (ObjectProxy::sendFinalize): New signal. (ObjectProxy::ObjectProxy): Connect/disconnect sendFinalize signal. (ObjectProxy::update, ObjectProxy::finalize): Use normal signal/slot connection. * interpreter-qobject.h, interpreter-qobject.cc (interpreter_qobject::ready): Rename from octave_ready_signal. Change all uses. (interpreter_qobject::execution_finished): Rename from octave_finished_singal. Change all uses. (interpreter_qobject::shutdown_finished): New signal. (interpreter_qobject::shutdown): New slot. (interpreter_qobject::execute): After interpreter finishes with normal execution, simply signal that execution has finished. Don't attempt to disable connecton to GUI or cleanup/delete interpreter. * octave-qobject.h, octave-qobject.cc (base_qobject::handle_interpreter_execution_finished): Rename from handle_octave_finished): Simply emit a signal requesting an orderly shutdown of the interpreter. Change all uses. (base_qobject::handle_interpreter_shutdown_finished): New slot. (base_qobject::request_interpreter_shutdown): New signal. (base_qobject::base_qobject): Connect request_interpreter_shutdown to interpreter_qobject::shutdown slot. * interpreter.h, interpreter.cc (interpreter::shutdown): Rename from cleanup and make public. (interpreter::~interpreter): Don't call cleanup here.
author John W. Eaton <jwe@octave.org>
date Fri, 22 May 2020 12:54:13 -0400
parents 265b386f8b20
children 60f3b8702ab7
line wrap: on
line source

////////////////////////////////////////////////////////////////////////
//
// Copyright (C) 2011-2020 The Octave Project Developers
//
// See the file COPYRIGHT.md in the top-level directory of this
// distribution or <https://octave.org/copyright/>.
//
// This file is part of Octave.
//
// Octave is free software: you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Octave is distributed in the hope that it will be useful, but
// WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Octave; see the file COPYING.  If not, see
// <https://www.gnu.org/licenses/>.
//
////////////////////////////////////////////////////////////////////////

#if defined (HAVE_CONFIG_H)
#  include "config.h"
#endif

#include <QCoreApplication>
#include <QString>
#include <QThread>

#include "Object.h"
#include "ObjectProxy.h"

#include "oct-mutex.h"
#include "utils.h"

namespace QtHandles
{

  ObjectProxy::ObjectProxy (Object *obj)
    : QObject (), m_object (nullptr)
  {
    init (obj);
  }

  void
  ObjectProxy::init (Object *obj)
  {
    if (obj != m_object)
      {
        if (m_object)
          {
            disconnect (this, SIGNAL (sendUpdate (int)),
                        m_object, SLOT (slotUpdate (int)));
            disconnect (this, SIGNAL (sendFinalize (void)),
                        m_object, SLOT (slotFinalize (void)));
            disconnect (this, SIGNAL (sendRedraw (void)),
                        m_object, SLOT (slotRedraw (void)));
            disconnect (this, SIGNAL (sendShow (void)),
                        m_object, SLOT (slotShow (void)));
            disconnect (this, SIGNAL (sendPrint (const QString&, const QString&)),
                        m_object, SLOT (slotPrint (const QString&, const QString&)));
          }

        m_object = obj;

        if (m_object)
          {
            connect (this, SIGNAL (sendUpdate (int)),
                     m_object, SLOT (slotUpdate (int)));
            connect (this, SIGNAL (sendFinalize (void)),
                     m_object, SLOT (slotFinalize (void)));
            connect (this, SIGNAL (sendRedraw (void)),
                     m_object, SLOT (slotRedraw (void)));
            connect (this, SIGNAL (sendShow (void)),
                     m_object, SLOT (slotShow (void)));
            connect (this, SIGNAL (sendPrint (const QString&, const QString&)),
                     m_object, SLOT (slotPrint (const QString&, const QString&)),
                     Qt::BlockingQueuedConnection);
          }
      }
  }

  void
  ObjectProxy::setObject (Object *obj)
  {
    finalize ();
    init (obj);
  }

  void
  ObjectProxy::update (int pId)
  {
    emit sendUpdate (pId);
  }

  void
  ObjectProxy::finalize (void)
  {
    emit sendFinalize ();
  }

  void
  ObjectProxy::redraw (void)
  {
    emit sendRedraw ();
  }

  void
  ObjectProxy::show (void)
  {
    emit sendShow ();
  }

  void
  ObjectProxy::print (const QString& file_cmd, const QString& term)
  {
    emit sendPrint (file_cmd, term);
  }

  uint8NDArray
  ObjectProxy::get_pixels (void)
  {
    uint8NDArray retval;

    // The ObjectProxy is generally ran from the interpreter thread
    // while the actual Figure (Object) lives in the gui thread.  The
    // following ensures synchronous execution of the Figure method and
    // allows retrieving a return value.

    Qt::ConnectionType t = Qt::BlockingQueuedConnection;

    if (QThread::currentThread () == QCoreApplication::instance ()->thread ())
      t = Qt::DirectConnection;

    QMetaObject::invokeMethod (m_object, "slotGetPixels", t,
                               Q_RETURN_ARG (uint8NDArray, retval));

    return retval;
  }

};