<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/memory/ref_counted.h"
#include "base/stringprintf.h"
#include "chrome/browser/extensions/extension_devtools_browsertest.h"
#include "chrome/browser/extensions/extension_error_reporter.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/browser/renderer_host/render_view_host.h"
#include "content/public/browser/devtools_agent_host_registry.h"
#include "content/public/browser/devtools_client_host.h"
#include "content/public/browser/devtools_manager.h"
#include "content/public/browser/web_contents.h"
#include "net/base/net_util.h"

using content::DevToolsAgentHost;
using content::DevToolsAgentHostRegistry;
using content::DevToolsClientHost;
using content::DevToolsManager;
using content::WebContents;

// Looks for an ExtensionHost whose URL has the given path component (including
// leading slash).  Also verifies that the expected number of hosts are loaded.
static ExtensionHost* FindHostWithPath(ExtensionProcessManager* manager,
                                       const std::string& path,
                                       int expected_hosts) {
  ExtensionHost* host = NULL;
  int num_hosts = 0;
  for (ExtensionProcessManager::const_iterator iter = manager->begin();
       iter != manager->end(); ++iter) {
    if ((*iter)->GetURL().path() == path) {
      EXPECT_FALSE(host);
      host = *iter;
    }
    num_hosts++;
  }
  EXPECT_EQ(expected_hosts, num_hosts);
  EXPECT_TRUE(host);
  return host;
}

// Tests for the experimental timeline extensions API.
IN_PROC_BROWSER_TEST_F(ExtensionDevToolsBrowserTest, TimelineApi) {
  ASSERT_TRUE(LoadExtension(
      test_data_dir_.AppendASCII("devtools").AppendASCII("timeline_api")));

  // Get the ExtensionHost that is hosting our background page.
  ExtensionProcessManager* manager =
      browser()->profile()->GetExtensionProcessManager();
  ExtensionHost* host = FindHostWithPath(manager, "/background.html", 1);

  // Grab a handle to the DevToolsManager so we can forward messages to it.
  DevToolsManager* devtools_manager = DevToolsManager::GetInstance();

  // Grab the tab_id of whatever tab happens to be first.
  WebContents* web_contents = browser()->GetWebContentsAt(0);
  ASSERT_TRUE(web_contents);
  int tab_id = ExtensionTabUtil::GetTabId(web_contents);

  // Test setup.
  bool result = false;
  std::wstring register_listeners_js = base::StringPrintf(
      L"setListenersOnTab(%d)", tab_id);
  ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
      host->render_view_host(), L"", register_listeners_js, &result));
  EXPECT_TRUE(result);

  // Setting the events should have caused an ExtensionDevToolsBridge to be
  // registered for the tab's RenderViewHost.
  DevToolsAgentHost* agent = DevToolsAgentHostRegistry::GetDevToolsAgentHost(
      web_contents->GetRenderViewHost());
  DevToolsClientHost* devtools_client_host =
      devtools_manager->GetDevToolsClientHostFor(agent);
  ASSERT_TRUE(devtools_client_host);

  // Test onPageEvent event.
  result = false;

  devtools_client_host->DispatchOnInspectorFrontend("");
  ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
      host->render_view_host(), L"", L"testReceivePageEvent()", &result));
  EXPECT_TRUE(result);

  // Test onTabClose event.
  result = false;
  devtools_manager->UnregisterDevToolsClientHostFor(
      DevToolsAgentHostRegistry::GetDevToolsAgentHost(
          web_contents->GetRenderViewHost()));
  ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
      host->render_view_host(), L"", L"testReceiveTabCloseEvent()", &result));
  EXPECT_TRUE(result);
}

// Tests that ref counting of listeners from multiple processes works.
IN_PROC_BROWSER_TEST_F(ExtensionDevToolsBrowserTest, ProcessRefCounting) {
  ASSERT_TRUE(LoadExtension(
      test_data_dir_.AppendASCII("devtools").AppendASCII("timeline_api")));

  // Get the ExtensionHost that is hosting our background page.
  ExtensionProcessManager* manager =
      browser()->profile()->GetExtensionProcessManager();
  ExtensionHost* host_one = FindHostWithPath(manager, "/background.html", 1);

  ASSERT_TRUE(LoadExtension(
      test_data_dir_.AppendASCII("devtools").AppendASCII("timeline_api_two")));
  ExtensionHost* host_two = FindHostWithPath(manager,
                                             "/background_two.html", 2);

  DevToolsManager* devtools_manager = DevToolsManager::GetInstance();

  // Grab the tab_id of whatever tab happens to be first.
  WebContents* web_contents = browser()->GetWebContentsAt(0);
  ASSERT_TRUE(web_contents);
  int tab_id = ExtensionTabUtil::GetTabId(web_contents);

  // Test setup.
  bool result = false;
  std::wstring register_listeners_js = base::StringPrintf(
      L"setListenersOnTab(%d)", tab_id);
  ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
      host_one->render_view_host(), L"", register_listeners_js, &result));
  EXPECT_TRUE(result);

  // Setting the event listeners should have caused an ExtensionDevToolsBridge
  // to be registered for the tab's RenderViewHost.
  ASSERT_TRUE(devtools_manager->GetDevToolsClientHostFor(
      DevToolsAgentHostRegistry::GetDevToolsAgentHost(
          web_contents->GetRenderViewHost())));

  // Register listeners from the second extension as well.
  std::wstring script = base::StringPrintf(L"registerListenersForTab(%d)",
                                           tab_id);
  ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
      host_two->render_view_host(), L"", script, &result));
  EXPECT_TRUE(result);

  // Removing the listeners from the first extension should leave the bridge
  // alive.
  result = false;
  ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
      host_one->render_view_host(), L"", L"unregisterListeners()", &result));
  EXPECT_TRUE(result);
  ASSERT_TRUE(devtools_manager->GetDevToolsClientHostFor(
      DevToolsAgentHostRegistry::GetDevToolsAgentHost(
          web_contents->GetRenderViewHost())));

  // Removing the listeners from the second extension should tear the bridge
  // down.
  result = false;
  ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
      host_two->render_view_host(), L"", L"unregisterListeners()", &result));
  EXPECT_TRUE(result);
  ASSERT_FALSE(devtools_manager->GetDevToolsClientHostFor(
      DevToolsAgentHostRegistry::GetDevToolsAgentHost(
          web_contents->GetRenderViewHost())));
}
<commit_msg>Mark ExtensionDevToolsBrowserTest.TimelineApi flaky for debugging.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "base/memory/ref_counted.h"
#include "base/stringprintf.h"
#include "chrome/browser/extensions/extension_devtools_browsertest.h"
#include "chrome/browser/extensions/extension_error_reporter.h"
#include "chrome/browser/extensions/extension_host.h"
#include "chrome/browser/extensions/extension_process_manager.h"
#include "chrome/browser/extensions/extension_service.h"
#include "chrome/browser/extensions/extension_tab_util.h"
#include "chrome/browser/profiles/profile.h"
#include "chrome/browser/tabs/tab_strip_model.h"
#include "chrome/browser/ui/browser_list.h"
#include "chrome/common/chrome_paths.h"
#include "chrome/common/url_constants.h"
#include "chrome/test/base/ui_test_utils.h"
#include "content/browser/renderer_host/render_view_host.h"
#include "content/public/browser/devtools_agent_host_registry.h"
#include "content/public/browser/devtools_client_host.h"
#include "content/public/browser/devtools_manager.h"
#include "content/public/browser/web_contents.h"
#include "net/base/net_util.h"

using content::DevToolsAgentHost;
using content::DevToolsAgentHostRegistry;
using content::DevToolsClientHost;
using content::DevToolsManager;
using content::WebContents;

// Looks for an ExtensionHost whose URL has the given path component (including
// leading slash).  Also verifies that the expected number of hosts are loaded.
static ExtensionHost* FindHostWithPath(ExtensionProcessManager* manager,
                                       const std::string& path,
                                       int expected_hosts) {
  ExtensionHost* host = NULL;
  int num_hosts = 0;
  for (ExtensionProcessManager::const_iterator iter = manager->begin();
       iter != manager->end(); ++iter) {
    if ((*iter)->GetURL().path() == path) {
      EXPECT_FALSE(host);
      host = *iter;
    }
    num_hosts++;
  }
  EXPECT_EQ(expected_hosts, num_hosts);
  EXPECT_TRUE(host);
  return host;
}

// Tests for the experimental timeline extensions API.
// http://crbug.com/69369  http://crbug.com/52544
IN_PROC_BROWSER_TEST_F(ExtensionDevToolsBrowserTest, FLAKY_TimelineApi) {
  ASSERT_TRUE(LoadExtension(
      test_data_dir_.AppendASCII("devtools").AppendASCII("timeline_api")));

  // Get the ExtensionHost that is hosting our background page.
  ExtensionProcessManager* manager =
      browser()->profile()->GetExtensionProcessManager();
  ExtensionHost* host = FindHostWithPath(manager, "/background.html", 1);

  // Grab a handle to the DevToolsManager so we can forward messages to it.
  DevToolsManager* devtools_manager = DevToolsManager::GetInstance();

  // Grab the tab_id of whatever tab happens to be first.
  WebContents* web_contents = browser()->GetWebContentsAt(0);
  ASSERT_TRUE(web_contents);
  int tab_id = ExtensionTabUtil::GetTabId(web_contents);

  // Test setup.
  bool result = false;
  std::wstring register_listeners_js = base::StringPrintf(
      L"setListenersOnTab(%d)", tab_id);
  ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
      host->render_view_host(), L"", register_listeners_js, &result));
  EXPECT_TRUE(result);

  // Setting the events should have caused an ExtensionDevToolsBridge to be
  // registered for the tab's RenderViewHost.
  DevToolsAgentHost* agent = DevToolsAgentHostRegistry::GetDevToolsAgentHost(
      web_contents->GetRenderViewHost());
  DevToolsClientHost* devtools_client_host =
      devtools_manager->GetDevToolsClientHostFor(agent);
  ASSERT_TRUE(devtools_client_host);

  // Test onPageEvent event.
  result = false;

  devtools_client_host->DispatchOnInspectorFrontend("");
  ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
      host->render_view_host(), L"", L"testReceivePageEvent()", &result));
  EXPECT_TRUE(result);

  // Test onTabClose event.
  result = false;
  devtools_manager->UnregisterDevToolsClientHostFor(
      DevToolsAgentHostRegistry::GetDevToolsAgentHost(
          web_contents->GetRenderViewHost()));
  ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
      host->render_view_host(), L"", L"testReceiveTabCloseEvent()", &result));
  EXPECT_TRUE(result);
}

// Tests that ref counting of listeners from multiple processes works.
IN_PROC_BROWSER_TEST_F(ExtensionDevToolsBrowserTest, ProcessRefCounting) {
  ASSERT_TRUE(LoadExtension(
      test_data_dir_.AppendASCII("devtools").AppendASCII("timeline_api")));

  // Get the ExtensionHost that is hosting our background page.
  ExtensionProcessManager* manager =
      browser()->profile()->GetExtensionProcessManager();
  ExtensionHost* host_one = FindHostWithPath(manager, "/background.html", 1);

  ASSERT_TRUE(LoadExtension(
      test_data_dir_.AppendASCII("devtools").AppendASCII("timeline_api_two")));
  ExtensionHost* host_two = FindHostWithPath(manager,
                                             "/background_two.html", 2);

  DevToolsManager* devtools_manager = DevToolsManager::GetInstance();

  // Grab the tab_id of whatever tab happens to be first.
  WebContents* web_contents = browser()->GetWebContentsAt(0);
  ASSERT_TRUE(web_contents);
  int tab_id = ExtensionTabUtil::GetTabId(web_contents);

  // Test setup.
  bool result = false;
  std::wstring register_listeners_js = base::StringPrintf(
      L"setListenersOnTab(%d)", tab_id);
  ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
      host_one->render_view_host(), L"", register_listeners_js, &result));
  EXPECT_TRUE(result);

  // Setting the event listeners should have caused an ExtensionDevToolsBridge
  // to be registered for the tab's RenderViewHost.
  ASSERT_TRUE(devtools_manager->GetDevToolsClientHostFor(
      DevToolsAgentHostRegistry::GetDevToolsAgentHost(
          web_contents->GetRenderViewHost())));

  // Register listeners from the second extension as well.
  std::wstring script = base::StringPrintf(L"registerListenersForTab(%d)",
                                           tab_id);
  ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
      host_two->render_view_host(), L"", script, &result));
  EXPECT_TRUE(result);

  // Removing the listeners from the first extension should leave the bridge
  // alive.
  result = false;
  ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
      host_one->render_view_host(), L"", L"unregisterListeners()", &result));
  EXPECT_TRUE(result);
  ASSERT_TRUE(devtools_manager->GetDevToolsClientHostFor(
      DevToolsAgentHostRegistry::GetDevToolsAgentHost(
          web_contents->GetRenderViewHost())));

  // Removing the listeners from the second extension should tear the bridge
  // down.
  result = false;
  ASSERT_TRUE(ui_test_utils::ExecuteJavaScriptAndExtractBool(
      host_two->render_view_host(), L"", L"unregisterListeners()", &result));
  EXPECT_TRUE(result);
  ASSERT_FALSE(devtools_manager->GetDevToolsClientHostFor(
      DevToolsAgentHostRegistry::GetDevToolsAgentHost(
          web_contents->GetRenderViewHost())));
}
<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: salnativewidgets.hxx,v $
 *
 *  $Revision: 1.2 $
 *
 *  last change: $Author: vg $ $Date: 2007-04-11 18:07:38 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _SV_NATIVEWIDGETS_HXX
#define _SV_NATIVEWIDGETS_HXX

#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring.hxx>
#endif

#ifndef _VCL_DLLAPI_H
#include <vcl/dllapi.h>
#endif

#ifndef _GEN_HXX
#include <tools/gen.hxx>
#endif

/* Control Types:
 *
 *   Specify the overall, whole control
 *   type (as opposed to parts of the
 *   control if it were composite).
 */

typedef sal_uInt32      ControlType;

// Normal PushButton/Command Button
#define CTRL_PUSHBUTTON         1

// Normal single radio button
#define CTRL_RADIOBUTTON            2

// Normal single checkbox
#define CTRL_CHECKBOX           10

// Combobox, i.e. a ListBox
// that allows data entry by user
#define CTRL_COMBOBOX           20

// Control that allows text entry
#define CTRL_EDITBOX            30

// Control that allows text entry, but without the usual border
// Has to be handled separately, because this one cannot handle
// HAS_BACKGROUND_TEXTURE, which is drawn in the edit box'es
// border window.
#define CTRL_EDITBOX_NOBORDER   31

// Control that allows text entry
// ( some systems distingish between single and multi line edit boxes )
#define CTRL_MULTILINE_EDITBOX 32

// Control that pops up a menu,
// but does NOT allow data entry
#define CTRL_LISTBOX            35

// An edit field together with two little
// buttons on the side (aka spin field)
#define CTRL_SPINBOX            40

// Two standalone spin buttons
// without an edit field
#define CTRL_SPINBUTTONS        45

// A single tab
#define CTRL_TAB_ITEM           50

// The border around a tab area,
// but without the tabs themselves.
// May have a gap at the top for
// the active tab
#define CTRL_TAB_PANE           55

// Background of a Tab Pane
#define CTRL_TAB_BODY           56

// Normal scrollbar, including
// all parts like slider, buttons
#define CTRL_SCROLLBAR          60

// Border around a group of related
// items, perhaps also displaying
// a label of identification
#define CTRL_GROUPBOX           70

// A separator line
#define CTRL_FIXEDLINE          80

// A rectangular border, like a
// Tab Pane, but without the
// possible gap for a tab
#define CTRL_FIXEDBORDER        90

// A toolbar control with buttons and a grip
#define CTRL_TOOLBAR            100

// The menubar
#define CTRL_MENUBAR            120
// popup menu
#define CTRL_MENU_POPUP         121

// The statusbar
#define CTRL_STATUSBAR          130

// tool tips
#define CTRL_TOOLTIP            140

/* Control Parts:
 *
 *   Uniquely identify a part of a control,
 *   for example the slider of a scroll bar.
 */

typedef sal_uInt32      ControlPart;

#define PART_ENTIRE_CONTROL     1
#define PART_WINDOW             5       // the static listbox window containing the list
#define PART_BUTTON             100
#define PART_BUTTON_UP          101
#define PART_BUTTON_DOWN            102 // Also for ComboBoxes/ListBoxes
#define PART_BUTTON_LEFT            103
#define PART_BUTTON_RIGHT       104
#define PART_ALL_BUTTONS            105
#define PART_TRACK_HORZ_LEFT        200
#define PART_TRACK_VERT_UPPER       201
#define PART_TRACK_HORZ_RIGHT       202
#define PART_TRACK_VERT_LOWER       203
#define PART_THUMB_HORZ         210 // Also used as toolbar grip
#define PART_THUMB_VERT         211 // Also used as toolbar grip
#define PART_MENU_ITEM              250
#define PART_MENU_ITEM_CHECK_MARK   251
#define PART_MENU_ITEM_RADIO_MARK   252

/** The edit field part of a control, e.g. of the combo box.

    Currently used just for combo boxes and just for GetNativeControlRegion().
    It is valid only if GetNativeControlRegion() supports PART_BUTTON_DOWN as
    well.
*/
#define PART_SUB_EDIT           300

// For controls that require the entire background
// to be drawn first, and then other pieces over top.
// (GTK+ scrollbars for example).  Control region passed
// in to draw this part is expected to be the entire
// area of the control.
// A control may respond to one or both.
#define PART_DRAW_BACKGROUND_HORZ       1000
#define PART_DRAW_BACKGROUND_VERT       1001

// GTK+ also draws tabs right->left since there is a
// hardcoded 2 pixel overlap between adjacent tabs
#define PART_TABS_DRAW_RTL          3000

// For themes that do not want to have the focus
// rectangle part drawn by VCL but take care of the
// whole inner control part by themselves
// eg, listboxes or comboboxes or spinbuttons
#define HAS_BACKGROUND_TEXTURE  4000

// For scrollbars that have 3 buttons (most KDE themes)
#define HAS_THREE_BUTTONS       5000

/* Control State:
 *
 *   Specify how a particular part of the control
 *   is to be drawn.  Constants are bitwise OR-ed
 *   together to compose a final drawing state.
 *   A _disabled_ state is assumed by the drawing
 *   functions until an ENABLED or HIDDEN is passed
 *   in the ControlState.
 */

typedef sal_uInt32      ControlState;

#define CTRL_STATE_ENABLED      0x0001
#define CTRL_STATE_FOCUSED      0x0002
#define CTRL_STATE_PRESSED      0x0004
#define CTRL_STATE_ROLLOVER     0x0008
#define CTRL_STATE_HIDDEN       0x0010
#define CTRL_STATE_DEFAULT      0x0020
#define CTRL_STATE_SELECTED     0x0040
#define CTRL_CACHING_ALLOWED    0x8000  // set when the control is completely visible (i.e. not clipped)

/* ButtonValue:
 *
 *   Identifies the tri-state value options
 *   that buttons allow
 */

enum ButtonValue {
    BUTTONVALUE_DONTKNOW,
    BUTTONVALUE_ON,
    BUTTONVALUE_OFF,
    BUTTONVALUE_MIXED
};

#ifdef __cplusplus

/* ScrollbarValue:
 *
 *   Value container for scrollbars.
 */
class VCL_DLLPUBLIC ScrollbarValue
{
    public:
        long            mnMin;
        long            mnMax;
        long            mnCur;
        long            mnVisibleSize;
        Rectangle       maThumbRect;
        Rectangle       maButton1Rect;
        Rectangle       maButton2Rect;
        ControlState    mnButton1State;
        ControlState    mnButton2State;
        ControlState    mnThumbState;
        ControlState    mnPage1State;
        ControlState    mnPage2State;

        inline ScrollbarValue()
                {
                    mnMin = 0; mnMax = 0; mnCur = 0; mnVisibleSize = 0;
                    mnButton1State = 0; mnButton2State = 0;
                    mnThumbState = 0; mnPage1State = 0; mnPage2State = 0;
                };
        inline ~ScrollbarValue() {};
};

/* TabitemValue:
 *
 *   Value container for tabitems.
 */

/* TABITEM constants are OR-ed together */
#define TABITEM_NOTALIGNED     0x000   // the tabitem is an inner item
#define TABITEM_LEFTALIGNED    0x001   // the tabitem is aligned with the left  border of the TabControl
#define TABITEM_RIGHTALIGNED   0x002   // the tabitem is aligned with the right border of the TabControl
#define TABITEM_FIRST_IN_GROUP 0x004   // the tabitem is the first in group of tabitems
#define TABITEM_LAST_IN_GROUP  0x008   // the tabitem is the last in group of tabitems

class VCL_DLLPUBLIC TabitemValue
{
    public:
        unsigned int    mnAlignment;

        inline TabitemValue()
                {
                    mnAlignment = 0;
                };
        inline ~TabitemValue() {};

        BOOL isLeftAligned()  { return (mnAlignment & TABITEM_LEFTALIGNED) != 0; }
        BOOL isRightAligned() { return (mnAlignment & TABITEM_RIGHTALIGNED) != 0; }
        BOOL isBothAligned()  { return isLeftAligned() && isRightAligned(); }
        BOOL isNotAligned()   { return (mnAlignment & (TABITEM_LEFTALIGNED | TABITEM_RIGHTALIGNED)) == 0; }
        BOOL isFirst()        { return (mnAlignment & TABITEM_FIRST_IN_GROUP) != 0; }
        BOOL isLast()         { return (mnAlignment & TABITEM_LAST_IN_GROUP) != 0; }
};

/* SpinbuttonValue:
 *
 *   Value container for spinbuttons to paint both buttons at once.
 *   Note: the other parameters of DrawNativeControl will have no meaning
 *         all parameters for spinbuttons are carried here
 */
class VCL_DLLPUBLIC SpinbuttonValue
{
    public:
        Rectangle       maUpperRect;
        Rectangle       maLowerRect;
        ControlState    mnUpperState;
        ControlState    mnLowerState;
        int         mnUpperPart;
        int         mnLowerPart;

        inline SpinbuttonValue()
                {
                    mnUpperState = mnLowerState = 0;
                };
        inline ~SpinbuttonValue() {};
};

/*  Toolbarvalue:
 *
 *  Value container for toolbars detailing the grip position
 */
class ToolbarValue
{
public:
    ToolbarValue()  { mbIsTopDockingArea = FALSE; }
    Rectangle           maGripRect;
    BOOL                mbIsTopDockingArea; // indicates that this is the top aligned dockingarea
                                            // adjacent to the menubar
};

/*  MenubarValue:
 *
 *  Value container for menubars specifying height of adjacent docking area
 */
class MenubarValue
{
public:
    MenubarValue() { maTopDockingAreaHeight=0; }
    int             maTopDockingAreaHeight;
};

/* ImplControlValue:
 *
 *   Generic value container for all control parts.
 */

class ImplControlValue
{
    friend class SalFrame;

    private:
        ButtonValue mTristate;  // Tristate value: on, off, mixed
        rtl::OUString   mString;        // string value
        long            mNumber;        // numeric value
        void *      mOptionalVal;   // optional control-specific value

    public:
        inline ImplControlValue( ButtonValue nTristate, rtl::OUString sString, long nNumeric, void * aOptVal ) \
                                { mTristate = nTristate; mString = sString; mNumber = nNumeric; mOptionalVal = aOptVal; };
        inline ImplControlValue( ButtonValue nTristate, rtl::OUString sString, long nNumeric ) \
                                { mTristate = nTristate; mString = sString; mNumber = nNumeric; mOptionalVal = NULL; };
        inline ImplControlValue( ButtonValue nTristate )    { mTristate = nTristate; mOptionalVal = NULL; };
        inline ImplControlValue( rtl::OUString sString )    { mString = sString; mOptionalVal = NULL; };
        inline ImplControlValue( long nNumeric )        { mNumber = nNumeric; mOptionalVal = NULL; };
        inline ImplControlValue( void * aOptVal )       { mOptionalVal = aOptVal; };
        inline ImplControlValue() { mTristate = BUTTONVALUE_DONTKNOW; mNumber = 0; mOptionalVal = NULL; };
        inline ~ImplControlValue() { mOptionalVal = NULL; };

        inline ButtonValue      getTristateVal( void ) const { return mTristate; }
        inline void         setTristateVal( ButtonValue nTristate ) { mTristate = nTristate; }

        inline const rtl::OUString& getStringVal( void ) const { return mString; }
        inline void         setStringVal( rtl::OUString sString ) { mString = sString; }

        inline long         getNumericVal( void ) const { return mNumber; }
        inline void         setNumericVal( long nNumeric ) { mNumber = nNumeric; }

        inline void *           getOptionalVal( void ) const { return mOptionalVal; }
        inline void         setOptionalVal( void * aOptVal ) { mOptionalVal = aOptVal; }
};

#endif  /* __cplusplus */

#endif

<commit_msg>INTEGRATION: CWS aquavcl01 (1.2.44); FILE MERGED 2007/06/22 07:07:50 pl 1.2.44.1: #i77552# add: native window background<commit_after>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: salnativewidgets.hxx,v $
 *
 *  $Revision: 1.3 $
 *
 *  last change: $Author: rt $ $Date: 2007-07-05 08:35:00 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library 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
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/

#ifndef _SV_NATIVEWIDGETS_HXX
#define _SV_NATIVEWIDGETS_HXX

#ifndef _RTL_USTRING_HXX_
#include <rtl/ustring.hxx>
#endif

#ifndef _VCL_DLLAPI_H
#include <vcl/dllapi.h>
#endif

#ifndef _GEN_HXX
#include <tools/gen.hxx>
#endif

/* Control Types:
 *
 *   Specify the overall, whole control
 *   type (as opposed to parts of the
 *   control if it were composite).
 */

typedef sal_uInt32      ControlType;

// Normal PushButton/Command Button
#define CTRL_PUSHBUTTON         1

// Normal single radio button
#define CTRL_RADIOBUTTON            2

// Normal single checkbox
#define CTRL_CHECKBOX           10

// Combobox, i.e. a ListBox
// that allows data entry by user
#define CTRL_COMBOBOX           20

// Control that allows text entry
#define CTRL_EDITBOX            30

// Control that allows text entry, but without the usual border
// Has to be handled separately, because this one cannot handle
// HAS_BACKGROUND_TEXTURE, which is drawn in the edit box'es
// border window.
#define CTRL_EDITBOX_NOBORDER   31

// Control that allows text entry
// ( some systems distingish between single and multi line edit boxes )
#define CTRL_MULTILINE_EDITBOX 32

// Control that pops up a menu,
// but does NOT allow data entry
#define CTRL_LISTBOX            35

// An edit field together with two little
// buttons on the side (aka spin field)
#define CTRL_SPINBOX            40

// Two standalone spin buttons
// without an edit field
#define CTRL_SPINBUTTONS        45

// A single tab
#define CTRL_TAB_ITEM           50

// The border around a tab area,
// but without the tabs themselves.
// May have a gap at the top for
// the active tab
#define CTRL_TAB_PANE           55

// Background of a Tab Pane
#define CTRL_TAB_BODY           56

// Normal scrollbar, including
// all parts like slider, buttons
#define CTRL_SCROLLBAR          60

// Border around a group of related
// items, perhaps also displaying
// a label of identification
#define CTRL_GROUPBOX           70

// A separator line
#define CTRL_FIXEDLINE          80

// A rectangular border, like a
// Tab Pane, but without the
// possible gap for a tab
#define CTRL_FIXEDBORDER        90

// A toolbar control with buttons and a grip
#define CTRL_TOOLBAR            100

// The menubar
#define CTRL_MENUBAR            120
// popup menu
#define CTRL_MENU_POPUP         121

// The statusbar
#define CTRL_STATUSBAR          130

// tool tips
#define CTRL_TOOLTIP            140

// to draw the implemented theme
#define CTRL_WINDOW_BACKGROUND  150

/* Control Parts:
 *
 *   Uniquely identify a part of a control,
 *   for example the slider of a scroll bar.
 */

typedef sal_uInt32      ControlPart;

#define PART_ENTIRE_CONTROL     1
#define PART_WINDOW             5       // the static listbox window containing the list
#define PART_BUTTON             100
#define PART_BUTTON_UP          101
#define PART_BUTTON_DOWN            102 // Also for ComboBoxes/ListBoxes
#define PART_BUTTON_LEFT            103
#define PART_BUTTON_RIGHT       104
#define PART_ALL_BUTTONS            105
#define PART_TRACK_HORZ_LEFT        200
#define PART_TRACK_VERT_UPPER       201
#define PART_TRACK_HORZ_RIGHT       202
#define PART_TRACK_VERT_LOWER       203
#define PART_THUMB_HORZ         210 // Also used as toolbar grip
#define PART_THUMB_VERT         211 // Also used as toolbar grip
#define PART_MENU_ITEM              250
#define PART_MENU_ITEM_CHECK_MARK   251
#define PART_MENU_ITEM_RADIO_MARK   252

/** The edit field part of a control, e.g. of the combo box.

    Currently used just for combo boxes and just for GetNativeControlRegion().
    It is valid only if GetNativeControlRegion() supports PART_BUTTON_DOWN as
    well.
*/
#define PART_SUB_EDIT           300

// For controls that require the entire background
// to be drawn first, and then other pieces over top.
// (GTK+ scrollbars for example).  Control region passed
// in to draw this part is expected to be the entire
// area of the control.
// A control may respond to one or both.
#define PART_DRAW_BACKGROUND_HORZ       1000
#define PART_DRAW_BACKGROUND_VERT       1001

// GTK+ also draws tabs right->left since there is a
// hardcoded 2 pixel overlap between adjacent tabs
#define PART_TABS_DRAW_RTL          3000

// For themes that do not want to have the focus
// rectangle part drawn by VCL but take care of the
// whole inner control part by themselves
// eg, listboxes or comboboxes or spinbuttons
#define HAS_BACKGROUND_TEXTURE  4000

// For scrollbars that have 3 buttons (most KDE themes)
#define HAS_THREE_BUTTONS       5000

#define PART_BACKGROUND_WINDOW  6000
#define PART_BACKGROUND_DIALOG  6001

/* Control State:
 *
 *   Specify how a particular part of the control
 *   is to be drawn.  Constants are bitwise OR-ed
 *   together to compose a final drawing state.
 *   A _disabled_ state is assumed by the drawing
 *   functions until an ENABLED or HIDDEN is passed
 *   in the ControlState.
 */

typedef sal_uInt32      ControlState;

#define CTRL_STATE_ENABLED      0x0001
#define CTRL_STATE_FOCUSED      0x0002
#define CTRL_STATE_PRESSED      0x0004
#define CTRL_STATE_ROLLOVER     0x0008
#define CTRL_STATE_HIDDEN       0x0010
#define CTRL_STATE_DEFAULT      0x0020
#define CTRL_STATE_SELECTED     0x0040
#define CTRL_CACHING_ALLOWED    0x8000  // set when the control is completely visible (i.e. not clipped)

/* ButtonValue:
 *
 *   Identifies the tri-state value options
 *   that buttons allow
 */

enum ButtonValue {
    BUTTONVALUE_DONTKNOW,
    BUTTONVALUE_ON,
    BUTTONVALUE_OFF,
    BUTTONVALUE_MIXED
};

#ifdef __cplusplus

/* ScrollbarValue:
 *
 *   Value container for scrollbars.
 */
class VCL_DLLPUBLIC ScrollbarValue
{
    public:
        long            mnMin;
        long            mnMax;
        long            mnCur;
        long            mnVisibleSize;
        Rectangle       maThumbRect;
        Rectangle       maButton1Rect;
        Rectangle       maButton2Rect;
        ControlState    mnButton1State;
        ControlState    mnButton2State;
        ControlState    mnThumbState;
        ControlState    mnPage1State;
        ControlState    mnPage2State;

        inline ScrollbarValue()
                {
                    mnMin = 0; mnMax = 0; mnCur = 0; mnVisibleSize = 0;
                    mnButton1State = 0; mnButton2State = 0;
                    mnThumbState = 0; mnPage1State = 0; mnPage2State = 0;
                };
        inline ~ScrollbarValue() {};
};

/* TabitemValue:
 *
 *   Value container for tabitems.
 */

/* TABITEM constants are OR-ed together */
#define TABITEM_NOTALIGNED     0x000   // the tabitem is an inner item
#define TABITEM_LEFTALIGNED    0x001   // the tabitem is aligned with the left  border of the TabControl
#define TABITEM_RIGHTALIGNED   0x002   // the tabitem is aligned with the right border of the TabControl
#define TABITEM_FIRST_IN_GROUP 0x004   // the tabitem is the first in group of tabitems
#define TABITEM_LAST_IN_GROUP  0x008   // the tabitem is the last in group of tabitems

class VCL_DLLPUBLIC TabitemValue
{
    public:
        unsigned int    mnAlignment;

        inline TabitemValue()
                {
                    mnAlignment = 0;
                };
        inline ~TabitemValue() {};

        BOOL isLeftAligned()  { return (mnAlignment & TABITEM_LEFTALIGNED) != 0; }
        BOOL isRightAligned() { return (mnAlignment & TABITEM_RIGHTALIGNED) != 0; }
        BOOL isBothAligned()  { return isLeftAligned() && isRightAligned(); }
        BOOL isNotAligned()   { return (mnAlignment & (TABITEM_LEFTALIGNED | TABITEM_RIGHTALIGNED)) == 0; }
        BOOL isFirst()        { return (mnAlignment & TABITEM_FIRST_IN_GROUP) != 0; }
        BOOL isLast()         { return (mnAlignment & TABITEM_LAST_IN_GROUP) != 0; }
};

/* SpinbuttonValue:
 *
 *   Value container for spinbuttons to paint both buttons at once.
 *   Note: the other parameters of DrawNativeControl will have no meaning
 *         all parameters for spinbuttons are carried here
 */
class VCL_DLLPUBLIC SpinbuttonValue
{
    public:
        Rectangle       maUpperRect;
        Rectangle       maLowerRect;
        ControlState    mnUpperState;
        ControlState    mnLowerState;
        int         mnUpperPart;
        int         mnLowerPart;

        inline SpinbuttonValue()
                {
                    mnUpperState = mnLowerState = 0;
                };
        inline ~SpinbuttonValue() {};
};

/*  Toolbarvalue:
 *
 *  Value container for toolbars detailing the grip position
 */
class ToolbarValue
{
public:
    ToolbarValue()  { mbIsTopDockingArea = FALSE; }
    Rectangle           maGripRect;
    BOOL                mbIsTopDockingArea; // indicates that this is the top aligned dockingarea
                                            // adjacent to the menubar
};

/*  MenubarValue:
 *
 *  Value container for menubars specifying height of adjacent docking area
 */
class MenubarValue
{
public:
    MenubarValue() { maTopDockingAreaHeight=0; }
    int             maTopDockingAreaHeight;
};

/* ImplControlValue:
 *
 *   Generic value container for all control parts.
 */

class ImplControlValue
{
    friend class SalFrame;

    private:
        ButtonValue mTristate;  // Tristate value: on, off, mixed
        rtl::OUString   mString;        // string value
        long            mNumber;        // numeric value
        void *      mOptionalVal;   // optional control-specific value

    public:
        inline ImplControlValue( ButtonValue nTristate, rtl::OUString sString, long nNumeric, void * aOptVal ) \
                                { mTristate = nTristate; mString = sString; mNumber = nNumeric; mOptionalVal = aOptVal; };
        inline ImplControlValue( ButtonValue nTristate, rtl::OUString sString, long nNumeric ) \
                                { mTristate = nTristate; mString = sString; mNumber = nNumeric; mOptionalVal = NULL; };
        inline ImplControlValue( ButtonValue nTristate )    { mTristate = nTristate; mOptionalVal = NULL; };
        inline ImplControlValue( rtl::OUString sString )    { mString = sString; mOptionalVal = NULL; };
        inline ImplControlValue( long nNumeric )        { mNumber = nNumeric; mOptionalVal = NULL; };
        inline ImplControlValue( void * aOptVal )       { mOptionalVal = aOptVal; };
        inline ImplControlValue() { mTristate = BUTTONVALUE_DONTKNOW; mNumber = 0; mOptionalVal = NULL; };
        inline ~ImplControlValue() { mOptionalVal = NULL; };

        inline ButtonValue      getTristateVal( void ) const { return mTristate; }
        inline void         setTristateVal( ButtonValue nTristate ) { mTristate = nTristate; }

        inline const rtl::OUString& getStringVal( void ) const { return mString; }
        inline void         setStringVal( rtl::OUString sString ) { mString = sString; }

        inline long         getNumericVal( void ) const { return mNumber; }
        inline void         setNumericVal( long nNumeric ) { mNumber = nNumeric; }

        inline void *           getOptionalVal( void ) const { return mOptionalVal; }
        inline void         setOptionalVal( void * aOptVal ) { mOptionalVal = aOptVal; }
};

#endif  /* __cplusplus */

#endif

<|endoftext|>


<commit_before>#include "exprcalculator.h"
#include "calculatingexceptions.h"

#include <QStack>
#include <QStringList>

#define _USE_MATH_DEFINES
#include <qmath.h>

ExprCalculator::ExprCalculator(QObject *parent) : QObject(parent)
{
	initializeBuiltInFunctions();
	initializeBuiltInConstants();
}

Number ExprCalculator::calculate(const RpnCodeThread &thread)
{
	RpnFunction function = {QList<QString>(), thread};
	m_functions.insert(RpnFunctionMain, function);

	return calculateFunction(RpnFunctionMain, QList<Number>());
}

Number ExprCalculator::calculateFunction(QString functionName, QList<Number> functionArguments)
{
	QStack<Number> calculationStack;

	RpnCodeThread currentThread = m_functions.value(functionName).codeThread;

	// Find and extract

	foreach (RpnElement element, currentThread) {

		switch (element.type) {
			// Just push to numbers stack
			case RpnElementOperand:
				calculationStack.push(element.value.value<Number>());
				break;

			// Get number and push to stack
			case RpnElementArgument:
				int argumentOrdinalNumber;
				argumentOrdinalNumber = element.value.value<RpnArgumentInfo>().ordinalNumber;
				calculationStack.push(functionArguments[argumentOrdinalNumber]);
				break;

			// Find constant and push its value
			case RpnElementConstant:
				if (m_builtInConstants.contains(element.value.value<QString>())) {
					calculationStack.push(m_builtInConstants.value(element.value.value<QString>()));
				}
				else if (m_constants.contains(element.value.value<QString>())) {
					calculationStack.push(m_constants.value(element.value.value<QString>()));
				}
				else {
					THROW(EIncorrectRpnCode());
				}

				break;

			// Find function and call it
			case RpnElementFunction: {
				QString calledFunctionName = element.value.value<QString>();

				if (m_builtInFunctions.contains(calledFunctionName)) {
					QList<Number> actualArguments;
					for (int i = 0; i < m_builtInFunctions.value(calledFunctionName); i++) {
						actualArguments.prepend(calculationStack.pop());
					}
					Number result = calculateBuiltInFunction(calledFunctionName, actualArguments);
					calculationStack.push(result);
				}

				else if (m_functions.contains(calledFunctionName)) {
					QList<Number> actualArguments;
					for (int i = 0; i < m_functions.value(calledFunctionName).arguments.count(); i++) {
						actualArguments.prepend(calculationStack.pop());
					}
					Number result = calculateFunction(calledFunctionName, actualArguments);
					calculationStack.push(result);
				}

				else {
					THROW(EIncorrectRpnCode());
				}
				break;
			}
			default:
				THROW(EIncorrectRpnCode());
		}
	}

	if (calculationStack.count() != 1) {
		THROW(EIncorrectRpnCode());
	}
	return calculationStack.pop();
}

Number ExprCalculator::calculateBuiltInFunction(QString functionName, QList<Number> functionArguments)
{
	if (functionName == RpnFunctionPlus) {
		return functionArguments[0] + functionArguments[1];
	}
	else if (functionName == RpnFunctionMinus) {
		return functionArguments[0] - functionArguments[1];
	}
	else if (functionName == RpnFunctionMultiply) {
		return functionArguments[0] * functionArguments[1];
	}
	else if (functionName == RpnFunctionDivide) {
		return functionArguments[0] / functionArguments[1];
	}
	else if (functionName == RpnFunctionPower) {
		return qPow(functionArguments[0],  functionArguments[1]);
	}
	else if (functionName == Sine) {
		return qSin(functionArguments[0]);
	}
	else if (functionName == Cosine) {
		return qCos(functionArguments[0]);
	}
	else if (functionName == Tangent) {
		return qTan(functionArguments[0]);
	} else {
		THROW(EIncorrectRpnCode());
	}

	// Compiler needs this useless thing
	return 0;
}

FunctionDescription ExprCalculator::functionDescriptionFromCode(const QString &functionName, RpnFunction functionCode)
{
	FunctionDescription description;
	description.name = functionName;
	description.arguments = functionCode.arguments;

	QStack<QString> functionBodyParts;

	foreach(RpnElement element, functionCode.codeThread) {

		QString operand;
		switch (element.type) {

			case RpnElementOperand:
				operand = QString::number(element.value.value<Number>());
				break;

			case RpnElementConstant:
				operand = element.value.toString();
				break;

			case RpnElementArgument: {
				RpnArgumentInfo argumentInfo = element.value.value<RpnArgumentInfo>();
				operand = argumentInfo.name;
				break;
			}

			case RpnElementFunction: {
				QString functionName = element.value.toString();

				// basic arithmetical operations
				if (functionName == RpnFunctionPlus) {
					QString right = functionBodyParts.pop();
					QString left = functionBodyParts.pop();
					operand = QString("(%1 + %2)").arg(left, right);
				}
				else if (functionName == RpnFunctionMinus) {
					QString right = functionBodyParts.pop();
					QString left = functionBodyParts.pop();
					operand = QString("(%1 − %2)").arg(left, right);
				}
				else if (functionName == RpnFunctionMultiply) {
					QString right = functionBodyParts.pop();
					QString left = functionBodyParts.pop();
					operand = QString("(%1 × %2)").arg(left, right);
				}
				else if (functionName == RpnFunctionDivide) {
					QString right = functionBodyParts.pop();
					QString left = functionBodyParts.pop();
					operand = QString("(%1 ÷ %2)").arg(left, right);
				}
				else if (functionName == RpnFunctionPower) {
					QString right = functionBodyParts.pop();
					QString left = functionBodyParts.pop();
					operand = QString("(%1 ^ %2)").arg(left, right);
				}

				// built-in and user-defined functions
				else {
					int argumentsCount;
					if (m_builtInFunctions.contains(functionName)) {
						argumentsCount = m_builtInFunctions.value(functionName);
					}
					else if (m_functions.contains(functionName)) {
						argumentsCount = m_functions.value(functionName).arguments.count();
					}
					else {
						THROW(EIncorrectRpnCode());
					}

					QStringList arguments;
					for (int i = 0; i < argumentsCount; i++) {
						arguments.prepend(functionBodyParts.pop());
						operand = QString("%1(%2)").arg(functionName).arg(arguments.join(", "));
					}
				}
				break;
			}
			default:
				THROW(EIncorrectRpnCode());
		} // switch
		functionBodyParts.push(operand);

	} // foreach

	if (functionBodyParts.count() != 1) {
		THROW(EIncorrectRpnCode());
	}

	description.body = functionBodyParts.pop();
	return description;
}

void ExprCalculator::addConstant(const QString &name, const Number &value)
{
	if (m_builtInConstants.contains(name)) {
		THROW(EBuiltInRedifinition(name, EBuiltInRedifinition::Constant));
	}

	m_constants.insert(name, value);
}

void ExprCalculator::addFunction(const QString &name, const RpnFunction &function)
{
	if (m_builtInFunctions.contains(name)) {
		THROW(EBuiltInRedifinition(name, EBuiltInRedifinition::Function));
	}

	if (m_functionNames.contains(name)) {
		m_functionNames.removeOne(name);
	}
	m_functionNames.append(name);
	m_functions.insert(name, function);
}

bool ExprCalculator::isFunction(const QString &name)
{
	return (m_functions.contains(name) || m_builtInFunctions.contains(name));
}

bool ExprCalculator::isConstant(const QString &name)
{
	return (m_constants.contains(name) || m_builtInConstants.contains(name));
}

int ExprCalculator::functionArgumentsCount(const QString &name)
{
	if (!isFunction(name)) {
		THROW(EIncorrectRpnCode());
	}

	if (m_functions.contains(name)) {
		return m_functions.value(name).arguments.count();
	}
	else {
		return m_builtInFunctions.value(name);
	}
}

QList<ConstantDescription> ExprCalculator::constantsList()
{
	QList<ConstantDescription> constantsList;

	QHashIterator<QString, Number> i(m_constants);
	while (i.hasNext()) {
		i.next();
		ConstantDescription constant = {i.key(), QString::number(i.value())};
		constantsList << constant;
	}

	return constantsList;
}

QList<FunctionDescription> ExprCalculator::functionsList()
{
	QList<FunctionDescription> functionsList;

	QHashIterator<QString, RpnFunction> i(m_functions);
	while (i.hasNext()) {
		i.next();
		if (i.key() != RpnFunctionMain) {
			FunctionDescription function = functionDescriptionFromCode(i.key(), i.value());
			functionsList << function;
		}
	}

	return functionsList;
}

void ExprCalculator::initializeBuiltInFunctions()
{
	m_builtInFunctions.insert(RpnFunctionMain, 0);
	m_builtInFunctions.insert(RpnFunctionPlus, 2);
	m_builtInFunctions.insert(RpnFunctionMinus, 2);
	m_builtInFunctions.insert(RpnFunctionMultiply, 2);
	m_builtInFunctions.insert(RpnFunctionDivide, 2);
	m_builtInFunctions.insert(RpnFunctionPower, 2);
	m_builtInFunctions.insert(Sine, 1);
	m_builtInFunctions.insert(Cosine, 1);
	m_builtInFunctions.insert(Tangent, 1);
}

void ExprCalculator::initializeBuiltInConstants()
{
	m_builtInConstants.insert(Pi, M_PI);
	m_builtInConstants.insert(E, M_E);
}
<commit_msg>Functions list enumerates functions in order of their declaration.<commit_after>#include "exprcalculator.h"
#include "calculatingexceptions.h"

#include <QStack>
#include <QStringList>

#define _USE_MATH_DEFINES
#include <qmath.h>

ExprCalculator::ExprCalculator(QObject *parent) : QObject(parent)
{
	initializeBuiltInFunctions();
	initializeBuiltInConstants();
}

Number ExprCalculator::calculate(const RpnCodeThread &thread)
{
	RpnFunction function = {QList<QString>(), thread};
	m_functions.insert(RpnFunctionMain, function);

	return calculateFunction(RpnFunctionMain, QList<Number>());
}

Number ExprCalculator::calculateFunction(QString functionName, QList<Number> functionArguments)
{
	QStack<Number> calculationStack;

	RpnCodeThread currentThread = m_functions.value(functionName).codeThread;

	// Find and extract

	foreach (RpnElement element, currentThread) {

		switch (element.type) {
			// Just push to numbers stack
			case RpnElementOperand:
				calculationStack.push(element.value.value<Number>());
				break;

			// Get number and push to stack
			case RpnElementArgument:
				int argumentOrdinalNumber;
				argumentOrdinalNumber = element.value.value<RpnArgumentInfo>().ordinalNumber;
				calculationStack.push(functionArguments[argumentOrdinalNumber]);
				break;

			// Find constant and push its value
			case RpnElementConstant:
				if (m_builtInConstants.contains(element.value.value<QString>())) {
					calculationStack.push(m_builtInConstants.value(element.value.value<QString>()));
				}
				else if (m_constants.contains(element.value.value<QString>())) {
					calculationStack.push(m_constants.value(element.value.value<QString>()));
				}
				else {
					THROW(EIncorrectRpnCode());
				}

				break;

			// Find function and call it
			case RpnElementFunction: {
				QString calledFunctionName = element.value.value<QString>();

				if (m_builtInFunctions.contains(calledFunctionName)) {
					QList<Number> actualArguments;
					for (int i = 0; i < m_builtInFunctions.value(calledFunctionName); i++) {
						actualArguments.prepend(calculationStack.pop());
					}
					Number result = calculateBuiltInFunction(calledFunctionName, actualArguments);
					calculationStack.push(result);
				}

				else if (m_functions.contains(calledFunctionName)) {
					QList<Number> actualArguments;
					for (int i = 0; i < m_functions.value(calledFunctionName).arguments.count(); i++) {
						actualArguments.prepend(calculationStack.pop());
					}
					Number result = calculateFunction(calledFunctionName, actualArguments);
					calculationStack.push(result);
				}

				else {
					THROW(EIncorrectRpnCode());
				}
				break;
			}
			default:
				THROW(EIncorrectRpnCode());
		}
	}

	if (calculationStack.count() != 1) {
		THROW(EIncorrectRpnCode());
	}
	return calculationStack.pop();
}

Number ExprCalculator::calculateBuiltInFunction(QString functionName, QList<Number> functionArguments)
{
	if (functionName == RpnFunctionPlus) {
		return functionArguments[0] + functionArguments[1];
	}
	else if (functionName == RpnFunctionMinus) {
		return functionArguments[0] - functionArguments[1];
	}
	else if (functionName == RpnFunctionMultiply) {
		return functionArguments[0] * functionArguments[1];
	}
	else if (functionName == RpnFunctionDivide) {
		return functionArguments[0] / functionArguments[1];
	}
	else if (functionName == RpnFunctionPower) {
		return qPow(functionArguments[0],  functionArguments[1]);
	}
	else if (functionName == Sine) {
		return qSin(functionArguments[0]);
	}
	else if (functionName == Cosine) {
		return qCos(functionArguments[0]);
	}
	else if (functionName == Tangent) {
		return qTan(functionArguments[0]);
	} else {
		THROW(EIncorrectRpnCode());
	}

	// Compiler needs this useless thing
	return 0;
}

FunctionDescription ExprCalculator::functionDescriptionFromCode(const QString &functionName, RpnFunction functionCode)
{
	FunctionDescription description;
	description.name = functionName;
	description.arguments = functionCode.arguments;

	QStack<QString> functionBodyParts;

	foreach(RpnElement element, functionCode.codeThread) {

		QString operand;
		switch (element.type) {

			case RpnElementOperand:
				operand = QString::number(element.value.value<Number>());
				break;

			case RpnElementConstant:
				operand = element.value.toString();
				break;

			case RpnElementArgument: {
				RpnArgumentInfo argumentInfo = element.value.value<RpnArgumentInfo>();
				operand = argumentInfo.name;
				break;
			}

			case RpnElementFunction: {
				QString functionName = element.value.toString();

				// basic arithmetical operations
				if (functionName == RpnFunctionPlus) {
					QString right = functionBodyParts.pop();
					QString left = functionBodyParts.pop();
					operand = QString("(%1 + %2)").arg(left, right);
				}
				else if (functionName == RpnFunctionMinus) {
					QString right = functionBodyParts.pop();
					QString left = functionBodyParts.pop();
					operand = QString("(%1 − %2)").arg(left, right);
				}
				else if (functionName == RpnFunctionMultiply) {
					QString right = functionBodyParts.pop();
					QString left = functionBodyParts.pop();
					operand = QString("(%1 × %2)").arg(left, right);
				}
				else if (functionName == RpnFunctionDivide) {
					QString right = functionBodyParts.pop();
					QString left = functionBodyParts.pop();
					operand = QString("(%1 ÷ %2)").arg(left, right);
				}
				else if (functionName == RpnFunctionPower) {
					QString right = functionBodyParts.pop();
					QString left = functionBodyParts.pop();
					operand = QString("(%1 ^ %2)").arg(left, right);
				}

				// built-in and user-defined functions
				else {
					int argumentsCount;
					if (m_builtInFunctions.contains(functionName)) {
						argumentsCount = m_builtInFunctions.value(functionName);
					}
					else if (m_functions.contains(functionName)) {
						argumentsCount = m_functions.value(functionName).arguments.count();
					}
					else {
						THROW(EIncorrectRpnCode());
					}

					QStringList arguments;
					for (int i = 0; i < argumentsCount; i++) {
						arguments.prepend(functionBodyParts.pop());
						operand = QString("%1(%2)").arg(functionName).arg(arguments.join(", "));
					}
				}
				break;
			}
			default:
				THROW(EIncorrectRpnCode());
		} // switch
		functionBodyParts.push(operand);

	} // foreach

	if (functionBodyParts.count() != 1) {
		THROW(EIncorrectRpnCode());
	}

	description.body = functionBodyParts.pop();
	return description;
}

void ExprCalculator::addConstant(const QString &name, const Number &value)
{
	if (m_builtInConstants.contains(name)) {
		THROW(EBuiltInRedifinition(name, EBuiltInRedifinition::Constant));
	}

	m_constants.insert(name, value);
}

void ExprCalculator::addFunction(const QString &name, const RpnFunction &function)
{
	if (m_builtInFunctions.contains(name)) {
		THROW(EBuiltInRedifinition(name, EBuiltInRedifinition::Function));
	}

	if (m_functionNames.contains(name)) {
		m_functionNames.removeOne(name);
	}
	m_functionNames.append(name);
	m_functions.insert(name, function);
}

bool ExprCalculator::isFunction(const QString &name)
{
	return (m_functions.contains(name) || m_builtInFunctions.contains(name));
}

bool ExprCalculator::isConstant(const QString &name)
{
	return (m_constants.contains(name) || m_builtInConstants.contains(name));
}

int ExprCalculator::functionArgumentsCount(const QString &name)
{
	if (!isFunction(name)) {
		THROW(EIncorrectRpnCode());
	}

	if (m_functions.contains(name)) {
		return m_functions.value(name).arguments.count();
	}
	else {
		return m_builtInFunctions.value(name);
	}
}

QList<ConstantDescription> ExprCalculator::constantsList()
{
	QList<ConstantDescription> constantsList;

	QHashIterator<QString, Number> i(m_constants);
	while (i.hasNext()) {
		i.next();
		ConstantDescription constant = {i.key(), QString::number(i.value())};
		constantsList << constant;
	}

	return constantsList;
}

QList<FunctionDescription> ExprCalculator::functionsList()
{
	QList<FunctionDescription> functionsList;

	foreach (QString functionName, m_functionNames) {
		if (functionName != RpnFunctionMain) {
			FunctionDescription function = functionDescriptionFromCode(functionName,
				m_functions.value(functionName));
			functionsList << function;
		}
	}

	return functionsList;
}

void ExprCalculator::initializeBuiltInFunctions()
{
	m_builtInFunctions.insert(RpnFunctionMain, 0);
	m_builtInFunctions.insert(RpnFunctionPlus, 2);
	m_builtInFunctions.insert(RpnFunctionMinus, 2);
	m_builtInFunctions.insert(RpnFunctionMultiply, 2);
	m_builtInFunctions.insert(RpnFunctionDivide, 2);
	m_builtInFunctions.insert(RpnFunctionPower, 2);
	m_builtInFunctions.insert(Sine, 1);
	m_builtInFunctions.insert(Cosine, 1);
	m_builtInFunctions.insert(Tangent, 1);
}

void ExprCalculator::initializeBuiltInConstants()
{
	m_builtInConstants.insert(Pi, M_PI);
	m_builtInConstants.insert(E, M_E);
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2011-2012 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2003-2006 The Regents of The University of Michigan
 * Copyright (c) 2011 Regents of the University of California
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Steve Reinhardt
 *          Lisa Hsu
 *          Nathan Binkert
 *          Ali Saidi
 *          Rick Strong
 */

#include "arch/isa_traits.hh"
#include "arch/remote_gdb.hh"
#include "arch/utility.hh"
#include "arch/vtophys.hh"
#include "base/loader/object_file.hh"
#include "base/loader/symtab.hh"
#include "base/str.hh"
#include "base/trace.hh"
#include "config/the_isa.hh"
#include "cpu/thread_context.hh"
#include "debug/Loader.hh"
#include "debug/WorkItems.hh"
#include "kern/kernel_stats.hh"
#include "mem/physical.hh"
#include "params/System.hh"
#include "sim/byteswap.hh"
#include "sim/debug.hh"
#include "sim/full_system.hh"
#include "sim/system.hh"

using namespace std;
using namespace TheISA;

vector<System *> System::systemList;

int System::numSystemsRunning = 0;

System::System(Params *p)
    : MemObject(p), _systemPort("system_port", this),
      _numContexts(0),
      pagePtr(0),
      init_param(p->init_param),
      physProxy(_systemPort),
      virtProxy(_systemPort),
      loadAddrMask(p->load_addr_mask),
      nextPID(0),
      physmem(p->memories),
      memoryMode(p->mem_mode),
      workItemsBegin(0),
      workItemsEnd(0),
      numWorkIds(p->num_work_ids),
      _params(p),
      totalNumInsts(0),
      instEventQueue("system instruction-based event queue")
{
    // add self to global system list
    systemList.push_back(this);

    if (FullSystem) {
        kernelSymtab = new SymbolTable;
        if (!debugSymbolTable)
            debugSymbolTable = new SymbolTable;
    }

    // Get the generic system master IDs
    MasterID tmp_id M5_VAR_USED;
    tmp_id = getMasterId("writebacks");
    assert(tmp_id == Request::wbMasterId);
    tmp_id = getMasterId("functional");
    assert(tmp_id == Request::funcMasterId);
    tmp_id = getMasterId("interrupt");
    assert(tmp_id == Request::intMasterId);

    if (FullSystem) {
        if (params()->kernel == "") {
            inform("No kernel set for full system simulation. "
                   "Assuming you know what you're doing\n");

            kernel = NULL;
        } else {
            // Get the kernel code
            kernel = createObjectFile(params()->kernel);
            inform("kernel located at: %s", params()->kernel);

            if (kernel == NULL)
                fatal("Could not load kernel file %s", params()->kernel);

            // setup entry points
            kernelStart = kernel->textBase();
            kernelEnd = kernel->bssBase() + kernel->bssSize();
            kernelEntry = kernel->entryPoint();

            // load symbols
            if (!kernel->loadGlobalSymbols(kernelSymtab))
                fatal("could not load kernel symbols\n");

            if (!kernel->loadLocalSymbols(kernelSymtab))
                fatal("could not load kernel local symbols\n");

            if (!kernel->loadGlobalSymbols(debugSymbolTable))
                fatal("could not load kernel symbols\n");

            if (!kernel->loadLocalSymbols(debugSymbolTable))
                fatal("could not load kernel local symbols\n");

            // Loading only needs to happen once and after memory system is
            // connected so it will happen in initState()
        }
    }

    // increment the number of running systms
    numSystemsRunning++;

    // Set back pointers to the system in all memories
    for (int x = 0; x < params()->memories.size(); x++)
        params()->memories[x]->system(this);
}

System::~System()
{
    delete kernelSymtab;
    delete kernel;

    for (uint32_t j = 0; j < numWorkIds; j++)
        delete workItemStats[j];
}

void
System::init()
{
    // check that the system port is connected
    if (!_systemPort.isConnected())
        panic("System port on %s is not connected.\n", name());
}

MasterPort&
System::getMasterPort(const std::string &if_name, int idx)
{
    // no need to distinguish at the moment (besides checking)
    return _systemPort;
}

void
System::setMemoryMode(Enums::MemoryMode mode)
{
    assert(getState() == Drained);
    memoryMode = mode;
}

bool System::breakpoint()
{
    if (remoteGDB.size())
        return remoteGDB[0]->breakpoint();
    return false;
}

/**
 * Setting rgdb_wait to a positive integer waits for a remote debugger to
 * connect to that context ID before continuing.  This should really
   be a parameter on the CPU object or something...
 */
int rgdb_wait = -1;

int
System::registerThreadContext(ThreadContext *tc, int assigned)
{
    int id;
    if (assigned == -1) {
        for (id = 0; id < threadContexts.size(); id++) {
            if (!threadContexts[id])
                break;
        }

        if (threadContexts.size() <= id)
            threadContexts.resize(id + 1);
    } else {
        if (threadContexts.size() <= assigned)
            threadContexts.resize(assigned + 1);
        id = assigned;
    }

    if (threadContexts[id])
        fatal("Cannot have two CPUs with the same id (%d)\n", id);

    threadContexts[id] = tc;
    _numContexts++;

    int port = getRemoteGDBPort();
    if (port) {
        RemoteGDB *rgdb = new RemoteGDB(this, tc);
        GDBListener *gdbl = new GDBListener(rgdb, port + id);
        gdbl->listen();

        if (rgdb_wait != -1 && rgdb_wait == id)
            gdbl->accept();

        if (remoteGDB.size() <= id) {
            remoteGDB.resize(id + 1);
        }

        remoteGDB[id] = rgdb;
    }

    activeCpus.push_back(false);

    return id;
}

int
System::numRunningContexts()
{
    int running = 0;
    for (int i = 0; i < _numContexts; ++i) {
        if (threadContexts[i]->status() != ThreadContext::Halted)
            ++running;
    }
    return running;
}

void
System::initState()
{
    if (FullSystem) {
        for (int i = 0; i < threadContexts.size(); i++)
            TheISA::startupCPU(threadContexts[i], i);
        // Moved from the constructor to here since it relies on the
        // address map being resolved in the interconnect
        /**
         * Load the kernel code into memory
         */
        if (params()->kernel != "")  {
            // Load program sections into memory
            kernel->loadSections(physProxy, loadAddrMask);

            DPRINTF(Loader, "Kernel start = %#x\n", kernelStart);
            DPRINTF(Loader, "Kernel end   = %#x\n", kernelEnd);
            DPRINTF(Loader, "Kernel entry = %#x\n", kernelEntry);
            DPRINTF(Loader, "Kernel loaded...\n");
        }
    }

    activeCpus.clear();
}

void
System::replaceThreadContext(ThreadContext *tc, int context_id)
{
    if (context_id >= threadContexts.size()) {
        panic("replaceThreadContext: bad id, %d >= %d\n",
              context_id, threadContexts.size());
    }

    threadContexts[context_id] = tc;
    if (context_id < remoteGDB.size())
        remoteGDB[context_id]->replaceThreadContext(tc);
}

Addr
System::allocPhysPages(int npages)
{
    Addr return_addr = pagePtr << LogVMPageSize;
    pagePtr += npages;
    if ((pagePtr << LogVMPageSize) > physmem.totalSize())
        fatal("Out of memory, please increase size of physical memory.");
    return return_addr;
}

Addr
System::memSize() const
{
    return physmem.totalSize();
}

Addr
System::freeMemSize() const
{
   return physmem.totalSize() - (pagePtr << LogVMPageSize);
}

bool
System::isMemAddr(Addr addr) const
{
    return physmem.isMemAddr(addr);
}

void
System::resume()
{
    SimObject::resume();
    totalNumInsts = 0;
}

void
System::serialize(ostream &os)
{
    if (FullSystem)
        kernelSymtab->serialize("kernel_symtab", os);
    SERIALIZE_SCALAR(pagePtr);
    SERIALIZE_SCALAR(nextPID);
}

void
System::unserialize(Checkpoint *cp, const string &section)
{
    if (FullSystem)
        kernelSymtab->unserialize("kernel_symtab", cp, section);
    UNSERIALIZE_SCALAR(pagePtr);
    UNSERIALIZE_SCALAR(nextPID);
}

void
System::regStats()
{
    for (uint32_t j = 0; j < numWorkIds ; j++) {
        workItemStats[j] = new Stats::Histogram();
        stringstream namestr;
        ccprintf(namestr, "work_item_type%d", j);
        workItemStats[j]->init(20)
                         .name(name() + "." + namestr.str())
                         .desc("Run time stat for" + namestr.str())
                         .prereq(*workItemStats[j]);
    }
}

void
System::workItemEnd(uint32_t tid, uint32_t workid)
{
    std::pair<uint32_t,uint32_t> p(tid, workid);
    if (!lastWorkItemStarted.count(p))
        return;

    Tick samp = curTick() - lastWorkItemStarted[p];
    DPRINTF(WorkItems, "Work item end: %d\t%d\t%lld\n", tid, workid, samp);

    if (workid >= numWorkIds)
        fatal("Got workid greater than specified in system configuration\n");

    workItemStats[workid]->sample(samp);
    lastWorkItemStarted.erase(p);
}

void
System::printSystems()
{
    vector<System *>::iterator i = systemList.begin();
    vector<System *>::iterator end = systemList.end();
    for (; i != end; ++i) {
        System *sys = *i;
        cerr << "System " << sys->name() << ": " << hex << sys << endl;
    }
}

void
printSystems()
{
    System::printSystems();
}

MasterID
System::getMasterId(std::string master_name)
{
    // strip off system name if the string starts with it
    if (startswith(master_name, name()))
        master_name = master_name.erase(0, name().size() + 1);

    // CPUs in switch_cpus ask for ids again after switching
    for (int i = 0; i < masterIds.size(); i++) {
        if (masterIds[i] == master_name) {
            return i;
        }
    }

    // Verify that the statistics haven't been enabled yet
    // Otherwise objects will have sized their stat buckets and
    // they will be too small

    if (Stats::enabled())
        fatal("Can't request a masterId after regStats(). \
                You must do so in init().\n");

    masterIds.push_back(master_name);

    return masterIds.size() - 1;
}

std::string
System::getMasterName(MasterID master_id)
{
    if (master_id >= masterIds.size())
        fatal("Invalid master_id passed to getMasterName()\n");

    return masterIds[master_id];
}

const char *System::MemoryModeStrings[3] = {"invalid", "atomic",
    "timing"};

System *
SystemParams::create()
{
    return new System(this);
}
<commit_msg>sim: add validation to make sure there is memory where we're loading the kernel<commit_after>/*
 * Copyright (c) 2011-2012 ARM Limited
 * All rights reserved
 *
 * The license below extends only to copyright in the software and shall
 * not be construed as granting a license to any other intellectual
 * property including but not limited to intellectual property relating
 * to a hardware implementation of the functionality of the software
 * licensed hereunder.  You may use the software subject to the license
 * terms below provided that you ensure that this notice is replicated
 * unmodified and in its entirety in all distributions of the software,
 * modified or unmodified, in source code or in binary form.
 *
 * Copyright (c) 2003-2006 The Regents of The University of Michigan
 * Copyright (c) 2011 Regents of the University of California
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are
 * met: redistributions of source code must retain the above copyright
 * notice, this list of conditions and the following disclaimer;
 * redistributions in binary form must reproduce the above copyright
 * notice, this list of conditions and the following disclaimer in the
 * documentation and/or other materials provided with the distribution;
 * neither the name of the copyright holders nor the names of its
 * contributors may be used to endorse or promote products derived from
 * this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 * Authors: Steve Reinhardt
 *          Lisa Hsu
 *          Nathan Binkert
 *          Ali Saidi
 *          Rick Strong
 */

#include "arch/isa_traits.hh"
#include "arch/remote_gdb.hh"
#include "arch/utility.hh"
#include "arch/vtophys.hh"
#include "base/loader/object_file.hh"
#include "base/loader/symtab.hh"
#include "base/str.hh"
#include "base/trace.hh"
#include "config/the_isa.hh"
#include "cpu/thread_context.hh"
#include "debug/Loader.hh"
#include "debug/WorkItems.hh"
#include "kern/kernel_stats.hh"
#include "mem/physical.hh"
#include "params/System.hh"
#include "sim/byteswap.hh"
#include "sim/debug.hh"
#include "sim/full_system.hh"
#include "sim/system.hh"

using namespace std;
using namespace TheISA;

vector<System *> System::systemList;

int System::numSystemsRunning = 0;

System::System(Params *p)
    : MemObject(p), _systemPort("system_port", this),
      _numContexts(0),
      pagePtr(0),
      init_param(p->init_param),
      physProxy(_systemPort),
      virtProxy(_systemPort),
      loadAddrMask(p->load_addr_mask),
      nextPID(0),
      physmem(p->memories),
      memoryMode(p->mem_mode),
      workItemsBegin(0),
      workItemsEnd(0),
      numWorkIds(p->num_work_ids),
      _params(p),
      totalNumInsts(0),
      instEventQueue("system instruction-based event queue")
{
    // add self to global system list
    systemList.push_back(this);

    if (FullSystem) {
        kernelSymtab = new SymbolTable;
        if (!debugSymbolTable)
            debugSymbolTable = new SymbolTable;
    }

    // Get the generic system master IDs
    MasterID tmp_id M5_VAR_USED;
    tmp_id = getMasterId("writebacks");
    assert(tmp_id == Request::wbMasterId);
    tmp_id = getMasterId("functional");
    assert(tmp_id == Request::funcMasterId);
    tmp_id = getMasterId("interrupt");
    assert(tmp_id == Request::intMasterId);

    if (FullSystem) {
        if (params()->kernel == "") {
            inform("No kernel set for full system simulation. "
                   "Assuming you know what you're doing\n");

            kernel = NULL;
        } else {
            // Get the kernel code
            kernel = createObjectFile(params()->kernel);
            inform("kernel located at: %s", params()->kernel);

            if (kernel == NULL)
                fatal("Could not load kernel file %s", params()->kernel);

            // setup entry points
            kernelStart = kernel->textBase();
            kernelEnd = kernel->bssBase() + kernel->bssSize();
            kernelEntry = kernel->entryPoint();

            // load symbols
            if (!kernel->loadGlobalSymbols(kernelSymtab))
                fatal("could not load kernel symbols\n");

            if (!kernel->loadLocalSymbols(kernelSymtab))
                fatal("could not load kernel local symbols\n");

            if (!kernel->loadGlobalSymbols(debugSymbolTable))
                fatal("could not load kernel symbols\n");

            if (!kernel->loadLocalSymbols(debugSymbolTable))
                fatal("could not load kernel local symbols\n");

            // Loading only needs to happen once and after memory system is
            // connected so it will happen in initState()
        }
    }

    // increment the number of running systms
    numSystemsRunning++;

    // Set back pointers to the system in all memories
    for (int x = 0; x < params()->memories.size(); x++)
        params()->memories[x]->system(this);
}

System::~System()
{
    delete kernelSymtab;
    delete kernel;

    for (uint32_t j = 0; j < numWorkIds; j++)
        delete workItemStats[j];
}

void
System::init()
{
    // check that the system port is connected
    if (!_systemPort.isConnected())
        panic("System port on %s is not connected.\n", name());
}

MasterPort&
System::getMasterPort(const std::string &if_name, int idx)
{
    // no need to distinguish at the moment (besides checking)
    return _systemPort;
}

void
System::setMemoryMode(Enums::MemoryMode mode)
{
    assert(getState() == Drained);
    memoryMode = mode;
}

bool System::breakpoint()
{
    if (remoteGDB.size())
        return remoteGDB[0]->breakpoint();
    return false;
}

/**
 * Setting rgdb_wait to a positive integer waits for a remote debugger to
 * connect to that context ID before continuing.  This should really
   be a parameter on the CPU object or something...
 */
int rgdb_wait = -1;

int
System::registerThreadContext(ThreadContext *tc, int assigned)
{
    int id;
    if (assigned == -1) {
        for (id = 0; id < threadContexts.size(); id++) {
            if (!threadContexts[id])
                break;
        }

        if (threadContexts.size() <= id)
            threadContexts.resize(id + 1);
    } else {
        if (threadContexts.size() <= assigned)
            threadContexts.resize(assigned + 1);
        id = assigned;
    }

    if (threadContexts[id])
        fatal("Cannot have two CPUs with the same id (%d)\n", id);

    threadContexts[id] = tc;
    _numContexts++;

    int port = getRemoteGDBPort();
    if (port) {
        RemoteGDB *rgdb = new RemoteGDB(this, tc);
        GDBListener *gdbl = new GDBListener(rgdb, port + id);
        gdbl->listen();

        if (rgdb_wait != -1 && rgdb_wait == id)
            gdbl->accept();

        if (remoteGDB.size() <= id) {
            remoteGDB.resize(id + 1);
        }

        remoteGDB[id] = rgdb;
    }

    activeCpus.push_back(false);

    return id;
}

int
System::numRunningContexts()
{
    int running = 0;
    for (int i = 0; i < _numContexts; ++i) {
        if (threadContexts[i]->status() != ThreadContext::Halted)
            ++running;
    }
    return running;
}

void
System::initState()
{
    if (FullSystem) {
        for (int i = 0; i < threadContexts.size(); i++)
            TheISA::startupCPU(threadContexts[i], i);
        // Moved from the constructor to here since it relies on the
        // address map being resolved in the interconnect
        /**
         * Load the kernel code into memory
         */
        if (params()->kernel != "")  {
            // Validate kernel mapping before loading binary
            if (!(isMemAddr(kernelStart & loadAddrMask) &&
                            isMemAddr(kernelEnd & loadAddrMask))) {
                fatal("Kernel is mapped to invalid location (not memory). "
                      "kernelStart 0x(%x) - kernelEnd 0x(%x)\n", kernelStart,
                      kernelEnd);
            }
            // Load program sections into memory
            kernel->loadSections(physProxy, loadAddrMask);

            DPRINTF(Loader, "Kernel start = %#x\n", kernelStart);
            DPRINTF(Loader, "Kernel end   = %#x\n", kernelEnd);
            DPRINTF(Loader, "Kernel entry = %#x\n", kernelEntry);
            DPRINTF(Loader, "Kernel loaded...\n");
        }
    }

    activeCpus.clear();
}

void
System::replaceThreadContext(ThreadContext *tc, int context_id)
{
    if (context_id >= threadContexts.size()) {
        panic("replaceThreadContext: bad id, %d >= %d\n",
              context_id, threadContexts.size());
    }

    threadContexts[context_id] = tc;
    if (context_id < remoteGDB.size())
        remoteGDB[context_id]->replaceThreadContext(tc);
}

Addr
System::allocPhysPages(int npages)
{
    Addr return_addr = pagePtr << LogVMPageSize;
    pagePtr += npages;
    if ((pagePtr << LogVMPageSize) > physmem.totalSize())
        fatal("Out of memory, please increase size of physical memory.");
    return return_addr;
}

Addr
System::memSize() const
{
    return physmem.totalSize();
}

Addr
System::freeMemSize() const
{
   return physmem.totalSize() - (pagePtr << LogVMPageSize);
}

bool
System::isMemAddr(Addr addr) const
{
    return physmem.isMemAddr(addr);
}

void
System::resume()
{
    SimObject::resume();
    totalNumInsts = 0;
}

void
System::serialize(ostream &os)
{
    if (FullSystem)
        kernelSymtab->serialize("kernel_symtab", os);
    SERIALIZE_SCALAR(pagePtr);
    SERIALIZE_SCALAR(nextPID);
}

void
System::unserialize(Checkpoint *cp, const string &section)
{
    if (FullSystem)
        kernelSymtab->unserialize("kernel_symtab", cp, section);
    UNSERIALIZE_SCALAR(pagePtr);
    UNSERIALIZE_SCALAR(nextPID);
}

void
System::regStats()
{
    for (uint32_t j = 0; j < numWorkIds ; j++) {
        workItemStats[j] = new Stats::Histogram();
        stringstream namestr;
        ccprintf(namestr, "work_item_type%d", j);
        workItemStats[j]->init(20)
                         .name(name() + "." + namestr.str())
                         .desc("Run time stat for" + namestr.str())
                         .prereq(*workItemStats[j]);
    }
}

void
System::workItemEnd(uint32_t tid, uint32_t workid)
{
    std::pair<uint32_t,uint32_t> p(tid, workid);
    if (!lastWorkItemStarted.count(p))
        return;

    Tick samp = curTick() - lastWorkItemStarted[p];
    DPRINTF(WorkItems, "Work item end: %d\t%d\t%lld\n", tid, workid, samp);

    if (workid >= numWorkIds)
        fatal("Got workid greater than specified in system configuration\n");

    workItemStats[workid]->sample(samp);
    lastWorkItemStarted.erase(p);
}

void
System::printSystems()
{
    vector<System *>::iterator i = systemList.begin();
    vector<System *>::iterator end = systemList.end();
    for (; i != end; ++i) {
        System *sys = *i;
        cerr << "System " << sys->name() << ": " << hex << sys << endl;
    }
}

void
printSystems()
{
    System::printSystems();
}

MasterID
System::getMasterId(std::string master_name)
{
    // strip off system name if the string starts with it
    if (startswith(master_name, name()))
        master_name = master_name.erase(0, name().size() + 1);

    // CPUs in switch_cpus ask for ids again after switching
    for (int i = 0; i < masterIds.size(); i++) {
        if (masterIds[i] == master_name) {
            return i;
        }
    }

    // Verify that the statistics haven't been enabled yet
    // Otherwise objects will have sized their stat buckets and
    // they will be too small

    if (Stats::enabled())
        fatal("Can't request a masterId after regStats(). \
                You must do so in init().\n");

    masterIds.push_back(master_name);

    return masterIds.size() - 1;
}

std::string
System::getMasterName(MasterID master_id)
{
    if (master_id >= masterIds.size())
        fatal("Invalid master_id passed to getMasterName()\n");

    return masterIds[master_id];
}

const char *System::MemoryModeStrings[3] = {"invalid", "atomic",
    "timing"};

System *
SystemParams::create()
{
    return new System(this);
}
<|endoftext|>


<commit_before>//   Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "paddle/fluid/imperative/nccl_context.h"

namespace paddle {
namespace imperative {
#if defined(PADDLE_WITH_CUDA) && !defined(_WIN32)
void NCCLParallelContext::RecvNCCLID(const std::string &ep,
                                     ncclUniqueId *nccl_id) {
  auto addr = paddle::string::Split(ep, ':');
  PADDLE_ENFORCE_EQ(addr.size(), 2UL,
                    "The endpoint should contain host and port: %s", ep);
  std::string host = addr[0];
  int port = std::stoi(addr[1]);

  int server_fd, new_socket;
  struct sockaddr_in address;
  int addrlen = sizeof(address);
  char buffer[1024] = {0};
  int opt = 0;
  // creating socket fd
  if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
    PADDLE_THROW("create server fd failed");
  if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT, &opt,
                 sizeof(opt)))
    PADDLE_THROW("set socket opt failed");

  address.sin_family = AF_INET;
  address.sin_addr.s_addr = INADDR_ANY;
  address.sin_port = htons(port);

  if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0)
    PADDLE_THROW("binding failed on ep: %s", ep);
  VLOG(3) << "listening on: " << ep;
  if (listen(server_fd, 3) < 0) PADDLE_THROW("listen on server fd failed");

  if ((new_socket =
           accept(server_fd, reinterpret_cast<struct sockaddr *>(&address),
                  reinterpret_cast<socklen_t *>(&addrlen))) < 0)
    PADDLE_THROW("accept the new socket fd failed");

  if (read(new_socket, buffer, 1024) < 0)
    PADDLE_THROW("reading the ncclUniqueId from socket failed");
  VLOG(3) << "recevived the ncclUniqueId";
  memcpy(nccl_id, buffer, NCCL_UNIQUE_ID_BYTES);

  VLOG(3) << "closing the socket server: " << ep;
  close(server_fd);
}

void NCCLParallelContext::SendNCCLID(const std::string &ep,
                                     ncclUniqueId *nccl_id) {
  auto addr = paddle::string::Split(ep, ':');
  PADDLE_ENFORCE_EQ(addr.size(), 2UL,
                    "The endpoint should contain host and port: %s", ep);
  std::string host = addr[0];
  int port = std::stoi(addr[1]);
  // struct sockaddr_in address;
  int sock = 0;
  struct sockaddr_in serv_addr;
  char buffer[1024] = {0};

  memcpy(buffer, nccl_id, NCCL_UNIQUE_ID_BYTES);
  if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    PADDLE_THROW("create socket failed");

  memset(&serv_addr, '0', sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_port = htons(port);

  if (inet_pton(AF_INET, host.c_str(), &serv_addr.sin_addr) <= 0)
    PADDLE_THROW("invalied address: %s", ep);

  while (true) {
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
      VLOG(0) << "worker: " << ep
              << " is not ready, will retry after 3 seconds...";
      std::this_thread::sleep_for(std::chrono::seconds(3));
      continue;
    }
    VLOG(3) << "sending the ncclUniqueId to " << ep;
    send(sock, buffer, NCCL_UNIQUE_ID_BYTES, 0);
    break;
  }
}

void NCCLParallelContext::BcastNCCLId(ncclUniqueId *nccl_id, int root) {
  if (strategy_.local_rank_ == root) {
    for (auto ep : strategy_.trainer_endpoints_) {
      if (ep != strategy_.current_endpoint_) SendNCCLID(ep, nccl_id);
    }
  } else {
    RecvNCCLID(strategy_.current_endpoint_, nccl_id);
  }
}

void NCCLParallelContext::Init() {
  ncclUniqueId nccl_id;
  ncclComm_t comm;
  if (strategy_.local_rank_ == 0) {
    // generate the unique ncclid on the root worker
    platform::dynload::ncclGetUniqueId(&nccl_id);
    BcastNCCLId(&nccl_id, 0);
  } else {
    BcastNCCLId(&nccl_id, 0);
  }
  int gpu_id = boost::get<platform::CUDAPlace>(place_).device;
  VLOG(0) << "init nccl context nranks: " << strategy_.nranks_
          << " local rank: " << strategy_.local_rank_ << " gpu id: " << gpu_id;

  PADDLE_ENFORCE(cudaSetDevice(gpu_id));
  PADDLE_ENFORCE(platform::dynload::ncclCommInitRank(
      &comm, strategy_.nranks_, nccl_id, strategy_.local_rank_));

  platform::DeviceContextPool &pool = platform::DeviceContextPool::Instance();
  auto *dev_ctx = static_cast<platform::CUDADeviceContext *>(pool.Get(place_));
  dev_ctx->set_nccl_comm(comm);
}
#endif

}  //  namespace imperative
}  //  namespace paddle
<commit_msg>disable reuse port test=develop (#16704)<commit_after>//   Copyright (c) 2019 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "paddle/fluid/imperative/nccl_context.h"

namespace paddle {
namespace imperative {
#if defined(PADDLE_WITH_CUDA) && !defined(_WIN32)
void NCCLParallelContext::RecvNCCLID(const std::string &ep,
                                     ncclUniqueId *nccl_id) {
  auto addr = paddle::string::Split(ep, ':');
  PADDLE_ENFORCE_EQ(addr.size(), 2UL,
                    "The endpoint should contain host and port: %s", ep);
  std::string host = addr[0];
  int port = std::stoi(addr[1]);

  int server_fd, new_socket;
  struct sockaddr_in address;
  int addrlen = sizeof(address);
  char buffer[1024] = {0};
  int opt = 0;
  // creating socket fd
  if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
    PADDLE_THROW("create server fd failed");
  if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)))
    PADDLE_THROW("set socket opt failed");

  address.sin_family = AF_INET;
  address.sin_addr.s_addr = INADDR_ANY;
  address.sin_port = htons(port);

  if (bind(server_fd, (struct sockaddr *)&address, sizeof(address)) < 0)
    PADDLE_THROW("binding failed on ep: %s", ep);
  VLOG(3) << "listening on: " << ep;
  if (listen(server_fd, 3) < 0) PADDLE_THROW("listen on server fd failed");

  if ((new_socket =
           accept(server_fd, reinterpret_cast<struct sockaddr *>(&address),
                  reinterpret_cast<socklen_t *>(&addrlen))) < 0)
    PADDLE_THROW("accept the new socket fd failed");

  if (read(new_socket, buffer, 1024) < 0)
    PADDLE_THROW("reading the ncclUniqueId from socket failed");
  VLOG(3) << "recevived the ncclUniqueId";
  memcpy(nccl_id, buffer, NCCL_UNIQUE_ID_BYTES);

  VLOG(3) << "closing the socket server: " << ep;
  close(server_fd);
}

void NCCLParallelContext::SendNCCLID(const std::string &ep,
                                     ncclUniqueId *nccl_id) {
  auto addr = paddle::string::Split(ep, ':');
  PADDLE_ENFORCE_EQ(addr.size(), 2UL,
                    "The endpoint should contain host and port: %s", ep);
  std::string host = addr[0];
  int port = std::stoi(addr[1]);
  // struct sockaddr_in address;
  int sock = 0;
  struct sockaddr_in serv_addr;
  char buffer[1024] = {0};

  memcpy(buffer, nccl_id, NCCL_UNIQUE_ID_BYTES);
  if ((sock = socket(AF_INET, SOCK_STREAM, 0)) < 0)
    PADDLE_THROW("create socket failed");

  memset(&serv_addr, '0', sizeof(serv_addr));
  serv_addr.sin_family = AF_INET;
  serv_addr.sin_port = htons(port);

  if (inet_pton(AF_INET, host.c_str(), &serv_addr.sin_addr) <= 0)
    PADDLE_THROW("invalied address: %s", ep);

  while (true) {
    if (connect(sock, (struct sockaddr *)&serv_addr, sizeof(serv_addr)) < 0) {
      VLOG(0) << "worker: " << ep
              << " is not ready, will retry after 3 seconds...";
      std::this_thread::sleep_for(std::chrono::seconds(3));
      continue;
    }
    VLOG(3) << "sending the ncclUniqueId to " << ep;
    send(sock, buffer, NCCL_UNIQUE_ID_BYTES, 0);
    break;
  }
}

void NCCLParallelContext::BcastNCCLId(ncclUniqueId *nccl_id, int root) {
  if (strategy_.local_rank_ == root) {
    for (auto ep : strategy_.trainer_endpoints_) {
      if (ep != strategy_.current_endpoint_) SendNCCLID(ep, nccl_id);
    }
  } else {
    RecvNCCLID(strategy_.current_endpoint_, nccl_id);
  }
}

void NCCLParallelContext::Init() {
  ncclUniqueId nccl_id;
  ncclComm_t comm;
  if (strategy_.local_rank_ == 0) {
    // generate the unique ncclid on the root worker
    platform::dynload::ncclGetUniqueId(&nccl_id);
    BcastNCCLId(&nccl_id, 0);
  } else {
    BcastNCCLId(&nccl_id, 0);
  }
  int gpu_id = boost::get<platform::CUDAPlace>(place_).device;
  VLOG(0) << "init nccl context nranks: " << strategy_.nranks_
          << " local rank: " << strategy_.local_rank_ << " gpu id: " << gpu_id;

  PADDLE_ENFORCE(cudaSetDevice(gpu_id));
  PADDLE_ENFORCE(platform::dynload::ncclCommInitRank(
      &comm, strategy_.nranks_, nccl_id, strategy_.local_rank_));

  platform::DeviceContextPool &pool = platform::DeviceContextPool::Instance();
  auto *dev_ctx = static_cast<platform::CUDADeviceContext *>(pool.Get(place_));
  dev_ctx->set_nccl_comm(comm);
}
#endif

}  //  namespace imperative
}  //  namespace paddle
<|endoftext|>