<commit_before>// Copyright (c) 2010 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 "chrome/browser/chromeos/login/wizard_accessibility_helper.h"

#include "base/logging.h"
#include "base/stl_util-inl.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/extension_accessibility_api.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/profile_manager.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "views/accelerator.h"
#include "views/view.h"

namespace chromeos {

scoped_ptr<views::Accelerator> WizardAccessibilityHelper::accelerator_;

// static
views::Accelerator WizardAccessibilityHelper::GetAccelerator() {
  if (!WizardAccessibilityHelper::accelerator_.get())
    WizardAccessibilityHelper::accelerator_.reset(
        new views::Accelerator(app::VKEY_Z, false, true, true));
  return *(WizardAccessibilityHelper::accelerator_.get());
}

// static
WizardAccessibilityHelper* WizardAccessibilityHelper::GetInstance() {
  return Singleton<WizardAccessibilityHelper>::get();
}

WizardAccessibilityHelper::WizardAccessibilityHelper() {
  accessibility_handler_.reset(new WizardAccessibilityHandler());
  profile_ = ProfileManager::GetDefaultProfile();
  registered_notifications_ = false;
}

void WizardAccessibilityHelper::RegisterNotifications() {
  registrar_.Add(accessibility_handler_.get(),
                 NotificationType::ACCESSIBILITY_CONTROL_FOCUSED,
                 NotificationService::AllSources());
  registrar_.Add(accessibility_handler_.get(),
                 NotificationType::ACCESSIBILITY_CONTROL_ACTION,
                 NotificationService::AllSources());
  registrar_.Add(accessibility_handler_.get(),
                 NotificationType::ACCESSIBILITY_TEXT_CHANGED,
                 NotificationService::AllSources());
  registrar_.Add(accessibility_handler_.get(),
                 NotificationType::ACCESSIBILITY_MENU_OPENED,
                 NotificationService::AllSources());
  registrar_.Add(accessibility_handler_.get(),
                 NotificationType::ACCESSIBILITY_MENU_CLOSED,
                 NotificationService::AllSources());
  registered_notifications_ = true;
}

void WizardAccessibilityHelper::UnregisterNotifications() {
  if (!registered_notifications_)
    return;
  registrar_.RemoveAll();
  registered_notifications_ = false;
}

void WizardAccessibilityHelper::MaybeEnableAccessibility(
    views::View* view_tree) {
  if (g_browser_process &&
      g_browser_process->local_state()->GetBoolean(
          prefs::kAccessibilityEnabled)) {
      EnableAccessibility(view_tree);
  } else {
    AddViewToBuffer(view_tree);
  }
}

void WizardAccessibilityHelper::MaybeSpeak(const char* str, bool queue,
    bool interruptible) {
  if (g_browser_process &&
      g_browser_process->local_state()->GetBoolean(
          prefs::kAccessibilityEnabled)) {
    accessibility_handler_->Speak(str, queue, interruptible);
  }
}

void WizardAccessibilityHelper::EnableAccessibility(views::View* view_tree) {
  VLOG(1) << "Enabling accessibility.";
  if (!registered_notifications_)
    RegisterNotifications();
  if (g_browser_process) {
    PrefService* prefService = g_browser_process->local_state();
    if (!prefService->GetBoolean(prefs::kAccessibilityEnabled)) {
      prefService->SetBoolean(prefs::kAccessibilityEnabled, true);
      prefService->ScheduleSavePersistentPrefs();
    }
  }
  ExtensionAccessibilityEventRouter::GetInstance()->
      SetAccessibilityEnabled(true);
  AddViewToBuffer(view_tree);
  // If accessibility pref is set, enable accessibility for all views in
  // the buffer for which access is not yet enabled.
  for (std::map<views::View*, bool>::iterator iter =
      views_buffer_.begin();
      iter != views_buffer_.end(); ++iter) {
    if (!(*iter).second) {
      AccessibleViewHelper *helper = new AccessibleViewHelper((*iter).first,
          profile_);
      accessible_view_helpers_.push_back(helper);
      (*iter).second = true;
    }
  }
}

void WizardAccessibilityHelper::AddViewToBuffer(views::View* view_tree) {
  if (!view_tree->GetWidget())
    return;
  bool view_exists = false;
  // Check if the view is already queued for enabling accessibility.
  // Prevent adding the same view in the buffer twice.
  for (std::map<views::View*, bool>::iterator iter = views_buffer_.begin();
      iter != views_buffer_.end(); ++iter) {
    if ((*iter).first == view_tree) {
      view_exists = true;
      break;
    }
  }
  if (!view_exists)
    views_buffer_[view_tree] = false;
}

}  // namespace chromeos
<commit_msg>Disable enable accessibility hotkey for ChromeOS login screen.<commit_after>// Copyright (c) 2010 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 "chrome/browser/chromeos/login/wizard_accessibility_helper.h"

#include "base/logging.h"
#include "base/stl_util-inl.h"
#include "chrome/browser/browser_process.h"
#include "chrome/browser/extensions/extension_accessibility_api.h"
#include "chrome/browser/prefs/pref_service.h"
#include "chrome/browser/profile.h"
#include "chrome/browser/profile_manager.h"
#include "chrome/common/notification_registrar.h"
#include "chrome/common/notification_service.h"
#include "chrome/common/pref_names.h"
#include "views/accelerator.h"
#include "views/view.h"

namespace chromeos {

scoped_ptr<views::Accelerator> WizardAccessibilityHelper::accelerator_;

// static
views::Accelerator WizardAccessibilityHelper::GetAccelerator() {
  // Use an accelerator that would never match any hotkey to temporarily
  // disable the accessibility hotkey per http://crosbug.com/9195
  // TODO(xiyuan): Change back to real hotkey as the following
  //      new views::Accelerator(app::VKEY_Z, false, true, true)
  if (!WizardAccessibilityHelper::accelerator_.get())
    WizardAccessibilityHelper::accelerator_.reset(
        new views::Accelerator(app::VKEY_UNKNOWN, 0xdeadbeef));
  return *(WizardAccessibilityHelper::accelerator_.get());
}

// static
WizardAccessibilityHelper* WizardAccessibilityHelper::GetInstance() {
  return Singleton<WizardAccessibilityHelper>::get();
}

WizardAccessibilityHelper::WizardAccessibilityHelper() {
  accessibility_handler_.reset(new WizardAccessibilityHandler());
  profile_ = ProfileManager::GetDefaultProfile();
  registered_notifications_ = false;
}

void WizardAccessibilityHelper::RegisterNotifications() {
  registrar_.Add(accessibility_handler_.get(),
                 NotificationType::ACCESSIBILITY_CONTROL_FOCUSED,
                 NotificationService::AllSources());
  registrar_.Add(accessibility_handler_.get(),
                 NotificationType::ACCESSIBILITY_CONTROL_ACTION,
                 NotificationService::AllSources());
  registrar_.Add(accessibility_handler_.get(),
                 NotificationType::ACCESSIBILITY_TEXT_CHANGED,
                 NotificationService::AllSources());
  registrar_.Add(accessibility_handler_.get(),
                 NotificationType::ACCESSIBILITY_MENU_OPENED,
                 NotificationService::AllSources());
  registrar_.Add(accessibility_handler_.get(),
                 NotificationType::ACCESSIBILITY_MENU_CLOSED,
                 NotificationService::AllSources());
  registered_notifications_ = true;
}

void WizardAccessibilityHelper::UnregisterNotifications() {
  if (!registered_notifications_)
    return;
  registrar_.RemoveAll();
  registered_notifications_ = false;
}

void WizardAccessibilityHelper::MaybeEnableAccessibility(
    views::View* view_tree) {
  if (g_browser_process &&
      g_browser_process->local_state()->GetBoolean(
          prefs::kAccessibilityEnabled)) {
      EnableAccessibility(view_tree);
  } else {
    AddViewToBuffer(view_tree);
  }
}

void WizardAccessibilityHelper::MaybeSpeak(const char* str, bool queue,
    bool interruptible) {
  if (g_browser_process &&
      g_browser_process->local_state()->GetBoolean(
          prefs::kAccessibilityEnabled)) {
    accessibility_handler_->Speak(str, queue, interruptible);
  }
}

void WizardAccessibilityHelper::EnableAccessibility(views::View* view_tree) {
  VLOG(1) << "Enabling accessibility.";
  if (!registered_notifications_)
    RegisterNotifications();
  if (g_browser_process) {
    PrefService* prefService = g_browser_process->local_state();
    if (!prefService->GetBoolean(prefs::kAccessibilityEnabled)) {
      prefService->SetBoolean(prefs::kAccessibilityEnabled, true);
      prefService->ScheduleSavePersistentPrefs();
    }
  }
  ExtensionAccessibilityEventRouter::GetInstance()->
      SetAccessibilityEnabled(true);
  AddViewToBuffer(view_tree);
  // If accessibility pref is set, enable accessibility for all views in
  // the buffer for which access is not yet enabled.
  for (std::map<views::View*, bool>::iterator iter =
      views_buffer_.begin();
      iter != views_buffer_.end(); ++iter) {
    if (!(*iter).second) {
      AccessibleViewHelper *helper = new AccessibleViewHelper((*iter).first,
          profile_);
      accessible_view_helpers_.push_back(helper);
      (*iter).second = true;
    }
  }
}

void WizardAccessibilityHelper::AddViewToBuffer(views::View* view_tree) {
  if (!view_tree->GetWidget())
    return;
  bool view_exists = false;
  // Check if the view is already queued for enabling accessibility.
  // Prevent adding the same view in the buffer twice.
  for (std::map<views::View*, bool>::iterator iter = views_buffer_.begin();
      iter != views_buffer_.end(); ++iter) {
    if ((*iter).first == view_tree) {
      view_exists = true;
      break;
    }
  }
  if (!view_exists)
    views_buffer_[view_tree] = false;
}

}  // namespace chromeos
<|endoftext|>


<commit_before>// Scintilla source code edit control
/** @file LexCSS.cxx
 ** Lexer for Cascade Style Sheets
 ** Written by Jakub Vrna
 **/
// Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

static inline bool IsAWordChar(const unsigned int ch) {
	return (isalnum(ch) || ch == '-' || ch >= 161);
}

inline bool IsCssOperator(const char ch) {
	if (!isalnum(ch) && (ch == '{' || ch == '}' || ch == ':' || ch == ',' || ch == ';' || ch == '.' || ch == '#' || ch == '!' || ch == '@'))
		return true;
	return false;
}

static void ColouriseCssDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) {
	WordList &keywords = *keywordlists[0];
	WordList &pseudoClasses = *keywordlists[1];

	StyleContext sc(startPos, length, initStyle, styler);

	int lastState = -1; // before operator
	int lastStateC = -1; // before comment
	int op = ' '; // last operator

	for (; sc.More(); sc.Forward()) {
		if (sc.state == SCE_CSS_COMMENT && sc.Match('*', '/')) {
			if (lastStateC == -1) {
				// backtrack to get last state
				unsigned int i = startPos;
				for (; i > 0; i--) {
					if ((lastStateC = styler.StyleAt(i-1)) != SCE_CSS_COMMENT) {
						if (lastStateC == SCE_CSS_OPERATOR) {
							op = styler.SafeGetCharAt(i-1);
							while (--i) {
								lastState = styler.StyleAt(i-1);
								if (lastState != SCE_CSS_OPERATOR && lastState != SCE_CSS_COMMENT)
									break;
							}
							if (i == 0)
								lastState = SCE_CSS_DEFAULT;
						}
						break;
					}
				}
				if (i == 0)
					lastStateC = SCE_CSS_DEFAULT;
			}
			sc.Forward();
			sc.ForwardSetState(lastStateC);
		}

		if (sc.state == SCE_CSS_COMMENT)
			continue;

		if (sc.state == SCE_CSS_OPERATOR) {
			if (op == ' ') {
				unsigned int i = startPos;
				op = styler.SafeGetCharAt(i-1);
				while (--i) {
					lastState = styler.StyleAt(i-1);
					if (lastState != SCE_CSS_OPERATOR && lastState != SCE_CSS_COMMENT)
						break;
				}
			}
			switch (op) {
			case '@':
				if (lastState == SCE_CSS_DEFAULT)
					sc.SetState(SCE_CSS_DIRECTIVE);
				break;
			case '{':
				if (lastState == SCE_CSS_DIRECTIVE)
					sc.SetState(SCE_CSS_DEFAULT);
				else if (lastState == SCE_CSS_TAG)
					sc.SetState(SCE_CSS_IDENTIFIER);
				break;
			case '}':
				if (lastState == SCE_CSS_DEFAULT || lastState == SCE_CSS_VALUE || lastState == SCE_CSS_IMPORTANT || lastState == SCE_CSS_IDENTIFIER)
					sc.SetState(SCE_CSS_DEFAULT);
				break;
			case ':':
				if (lastState == SCE_CSS_TAG || lastState == SCE_CSS_DEFAULT || lastState == SCE_CSS_CLASS || lastState == SCE_CSS_ID)
					sc.SetState(SCE_CSS_PSEUDOCLASS);
				else if (lastState == SCE_CSS_IDENTIFIER || lastState == SCE_CSS_UNKNOWN_IDENTIFIER)
					sc.SetState(SCE_CSS_VALUE);
				break;
			case '.':
				if (lastState == SCE_CSS_TAG || lastState == SCE_CSS_DEFAULT)
					sc.SetState(SCE_CSS_CLASS);
				break;
			case '#':
				if (lastState == SCE_CSS_TAG || lastState == SCE_CSS_DEFAULT)
					sc.SetState(SCE_CSS_ID);
				break;
			case ',':
				if (lastState == SCE_CSS_TAG)
					sc.SetState(SCE_CSS_DEFAULT);
				break;
			case ';':
				if (lastState == SCE_CSS_DIRECTIVE)
					sc.SetState(SCE_CSS_DEFAULT);
				else if (lastState == SCE_CSS_VALUE || lastState == SCE_CSS_IMPORTANT)
					sc.SetState(SCE_CSS_IDENTIFIER);
				break;
			case '!':
				if (lastState == SCE_CSS_VALUE)
					sc.SetState(SCE_CSS_IMPORTANT);
				break;
			}
		}

		if (IsAWordChar(sc.ch)) {
			if (sc.state == SCE_CSS_DEFAULT)
				sc.SetState(SCE_CSS_TAG);
			continue;
		}

		if (IsAWordChar(sc.chPrev) && (
			sc.state == SCE_CSS_IDENTIFIER || sc.state == SCE_CSS_UNKNOWN_IDENTIFIER
			|| sc.state == SCE_CSS_PSEUDOCLASS || sc.state == SCE_CSS_UNKNOWN_PSEUDOCLASS
			|| sc.state == SCE_CSS_IMPORTANT
		)) {
			char s[100];
			sc.GetCurrentLowered(s, sizeof(s));
			char *s2 = s;
			while (*s2 && !IsAWordChar(*s2))
				s2++;
			switch (sc.state) {
			case SCE_CSS_IDENTIFIER:
				if (!keywords.InList(s2))
					sc.ChangeState(SCE_CSS_UNKNOWN_IDENTIFIER);
				break;
			case SCE_CSS_UNKNOWN_IDENTIFIER:
				if (keywords.InList(s2))
					sc.ChangeState(SCE_CSS_IDENTIFIER);
				break;
			case SCE_CSS_PSEUDOCLASS:
				if (!pseudoClasses.InList(s2))
					sc.ChangeState(SCE_CSS_UNKNOWN_PSEUDOCLASS);
				break;
			case SCE_CSS_UNKNOWN_PSEUDOCLASS:
				if (pseudoClasses.InList(s2))
					sc.ChangeState(SCE_CSS_PSEUDOCLASS);
				break;
			case SCE_CSS_IMPORTANT:
				if (strcmp(s2, "important") != 0)
					sc.ChangeState(SCE_CSS_VALUE);
				break;
			}
		}

		if (sc.ch != '.' && sc.ch != ':' && sc.ch != '#' && (sc.state == SCE_CSS_CLASS || sc.state == SCE_CSS_PSEUDOCLASS || sc.state == SCE_CSS_UNKNOWN_PSEUDOCLASS || sc.state == SCE_CSS_UNKNOWN_PSEUDOCLASS || sc.state == SCE_CSS_ID))
			sc.SetState(SCE_CSS_TAG);

		if (sc.Match('/', '*')) {
			lastStateC = sc.state;
			sc.SetState(SCE_CSS_COMMENT);
			sc.Forward();
			continue;
		}

		if (IsCssOperator(static_cast<char>(sc.ch))
		&& (sc.state != SCE_CSS_VALUE || sc.ch == ';' || sc.ch == '}' || sc.ch == '!')
		&& (sc.state != SCE_CSS_DIRECTIVE || sc.ch == ';' || sc.ch == '{')
		) {
			if (sc.state != SCE_CSS_OPERATOR)
				lastState = sc.state;
			sc.SetState(SCE_CSS_OPERATOR);
			op = sc.ch;
		}
	}

	sc.Complete();
}

static void FoldCSSDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) {
	bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
	bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
	unsigned int endPos = startPos + length;
	int visibleChars = 0;
	int lineCurrent = styler.GetLine(startPos);
	int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
	int levelCurrent = levelPrev;
	char chNext = styler[startPos];
	bool inComment = (styler.StyleAt(startPos-1) == SCE_CSS_COMMENT);
	for (unsigned int i = startPos; i < endPos; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);
		int style = styler.StyleAt(i);
		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
		if (foldComment) {
			if (!inComment && (style == SCE_CSS_COMMENT))
				levelCurrent++;
			else if (inComment && (style != SCE_CSS_COMMENT))
				levelCurrent--;
			inComment = (style == SCE_CSS_COMMENT);
		}
		if (style == SCE_CSS_OPERATOR) {
			if (ch == '{') {
				levelCurrent++;
			} else if (ch == '}') {
				levelCurrent--;
			}
		}
		if (atEOL) {
			int lev = levelPrev;
			if (visibleChars == 0 && foldCompact)
				lev |= SC_FOLDLEVELWHITEFLAG;
			if ((levelCurrent > levelPrev) && (visibleChars > 0))
				lev |= SC_FOLDLEVELHEADERFLAG;
			if (lev != styler.LevelAt(lineCurrent)) {
				styler.SetLevel(lineCurrent, lev);
			}
			lineCurrent++;
			levelPrev = levelCurrent;
			visibleChars = 0;
		}
		if (!isspacechar(ch))
			visibleChars++;
	}
	// Fill in the real level of the next line, keeping the current flags as they will be filled in later
	int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
	styler.SetLevel(lineCurrent, levelPrev | flagsNext);
}

LexerModule lmCss(SCLEX_CSS, ColouriseCssDoc, "css", FoldCSSDoc);
<commit_msg>Upgraded keyword list descriptions from Brian Quinlan.<commit_after>// Scintilla source code edit control
/** @file LexCSS.cxx
 ** Lexer for Cascade Style Sheets
 ** Written by Jakub Vrna
 **/
// Copyright 1998-2002 by Neil Hodgson <neilh@scintilla.org>
// The License.txt file describes the conditions under which this software may be distributed.

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <stdio.h>
#include <stdarg.h>

#include "Platform.h"

#include "PropSet.h"
#include "Accessor.h"
#include "StyleContext.h"
#include "KeyWords.h"
#include "Scintilla.h"
#include "SciLexer.h"

static inline bool IsAWordChar(const unsigned int ch) {
	return (isalnum(ch) || ch == '-' || ch >= 161);
}

inline bool IsCssOperator(const char ch) {
	if (!isalnum(ch) && (ch == '{' || ch == '}' || ch == ':' || ch == ',' || ch == ';' || ch == '.' || ch == '#' || ch == '!' || ch == '@'))
		return true;
	return false;
}

static void ColouriseCssDoc(unsigned int startPos, int length, int initStyle, WordList *keywordlists[], Accessor &styler) {
	WordList &keywords = *keywordlists[0];
	WordList &pseudoClasses = *keywordlists[1];

	StyleContext sc(startPos, length, initStyle, styler);

	int lastState = -1; // before operator
	int lastStateC = -1; // before comment
	int op = ' '; // last operator

	for (; sc.More(); sc.Forward()) {
		if (sc.state == SCE_CSS_COMMENT && sc.Match('*', '/')) {
			if (lastStateC == -1) {
				// backtrack to get last state
				unsigned int i = startPos;
				for (; i > 0; i--) {
					if ((lastStateC = styler.StyleAt(i-1)) != SCE_CSS_COMMENT) {
						if (lastStateC == SCE_CSS_OPERATOR) {
							op = styler.SafeGetCharAt(i-1);
							while (--i) {
								lastState = styler.StyleAt(i-1);
								if (lastState != SCE_CSS_OPERATOR && lastState != SCE_CSS_COMMENT)
									break;
							}
							if (i == 0)
								lastState = SCE_CSS_DEFAULT;
						}
						break;
					}
				}
				if (i == 0)
					lastStateC = SCE_CSS_DEFAULT;
			}
			sc.Forward();
			sc.ForwardSetState(lastStateC);
		}

		if (sc.state == SCE_CSS_COMMENT)
			continue;

		if (sc.state == SCE_CSS_OPERATOR) {
			if (op == ' ') {
				unsigned int i = startPos;
				op = styler.SafeGetCharAt(i-1);
				while (--i) {
					lastState = styler.StyleAt(i-1);
					if (lastState != SCE_CSS_OPERATOR && lastState != SCE_CSS_COMMENT)
						break;
				}
			}
			switch (op) {
			case '@':
				if (lastState == SCE_CSS_DEFAULT)
					sc.SetState(SCE_CSS_DIRECTIVE);
				break;
			case '{':
				if (lastState == SCE_CSS_DIRECTIVE)
					sc.SetState(SCE_CSS_DEFAULT);
				else if (lastState == SCE_CSS_TAG)
					sc.SetState(SCE_CSS_IDENTIFIER);
				break;
			case '}':
				if (lastState == SCE_CSS_DEFAULT || lastState == SCE_CSS_VALUE || lastState == SCE_CSS_IMPORTANT || lastState == SCE_CSS_IDENTIFIER)
					sc.SetState(SCE_CSS_DEFAULT);
				break;
			case ':':
				if (lastState == SCE_CSS_TAG || lastState == SCE_CSS_DEFAULT || lastState == SCE_CSS_CLASS || lastState == SCE_CSS_ID)
					sc.SetState(SCE_CSS_PSEUDOCLASS);
				else if (lastState == SCE_CSS_IDENTIFIER || lastState == SCE_CSS_UNKNOWN_IDENTIFIER)
					sc.SetState(SCE_CSS_VALUE);
				break;
			case '.':
				if (lastState == SCE_CSS_TAG || lastState == SCE_CSS_DEFAULT)
					sc.SetState(SCE_CSS_CLASS);
				break;
			case '#':
				if (lastState == SCE_CSS_TAG || lastState == SCE_CSS_DEFAULT)
					sc.SetState(SCE_CSS_ID);
				break;
			case ',':
				if (lastState == SCE_CSS_TAG)
					sc.SetState(SCE_CSS_DEFAULT);
				break;
			case ';':
				if (lastState == SCE_CSS_DIRECTIVE)
					sc.SetState(SCE_CSS_DEFAULT);
				else if (lastState == SCE_CSS_VALUE || lastState == SCE_CSS_IMPORTANT)
					sc.SetState(SCE_CSS_IDENTIFIER);
				break;
			case '!':
				if (lastState == SCE_CSS_VALUE)
					sc.SetState(SCE_CSS_IMPORTANT);
				break;
			}
		}

		if (IsAWordChar(sc.ch)) {
			if (sc.state == SCE_CSS_DEFAULT)
				sc.SetState(SCE_CSS_TAG);
			continue;
		}

		if (IsAWordChar(sc.chPrev) && (
			sc.state == SCE_CSS_IDENTIFIER || sc.state == SCE_CSS_UNKNOWN_IDENTIFIER
			|| sc.state == SCE_CSS_PSEUDOCLASS || sc.state == SCE_CSS_UNKNOWN_PSEUDOCLASS
			|| sc.state == SCE_CSS_IMPORTANT
		)) {
			char s[100];
			sc.GetCurrentLowered(s, sizeof(s));
			char *s2 = s;
			while (*s2 && !IsAWordChar(*s2))
				s2++;
			switch (sc.state) {
			case SCE_CSS_IDENTIFIER:
				if (!keywords.InList(s2))
					sc.ChangeState(SCE_CSS_UNKNOWN_IDENTIFIER);
				break;
			case SCE_CSS_UNKNOWN_IDENTIFIER:
				if (keywords.InList(s2))
					sc.ChangeState(SCE_CSS_IDENTIFIER);
				break;
			case SCE_CSS_PSEUDOCLASS:
				if (!pseudoClasses.InList(s2))
					sc.ChangeState(SCE_CSS_UNKNOWN_PSEUDOCLASS);
				break;
			case SCE_CSS_UNKNOWN_PSEUDOCLASS:
				if (pseudoClasses.InList(s2))
					sc.ChangeState(SCE_CSS_PSEUDOCLASS);
				break;
			case SCE_CSS_IMPORTANT:
				if (strcmp(s2, "important") != 0)
					sc.ChangeState(SCE_CSS_VALUE);
				break;
			}
		}

		if (sc.ch != '.' && sc.ch != ':' && sc.ch != '#' && (sc.state == SCE_CSS_CLASS || sc.state == SCE_CSS_PSEUDOCLASS || sc.state == SCE_CSS_UNKNOWN_PSEUDOCLASS || sc.state == SCE_CSS_UNKNOWN_PSEUDOCLASS || sc.state == SCE_CSS_ID))
			sc.SetState(SCE_CSS_TAG);

		if (sc.Match('/', '*')) {
			lastStateC = sc.state;
			sc.SetState(SCE_CSS_COMMENT);
			sc.Forward();
			continue;
		}

		if (IsCssOperator(static_cast<char>(sc.ch))
		&& (sc.state != SCE_CSS_VALUE || sc.ch == ';' || sc.ch == '}' || sc.ch == '!')
		&& (sc.state != SCE_CSS_DIRECTIVE || sc.ch == ';' || sc.ch == '{')
		) {
			if (sc.state != SCE_CSS_OPERATOR)
				lastState = sc.state;
			sc.SetState(SCE_CSS_OPERATOR);
			op = sc.ch;
		}
	}

	sc.Complete();
}

static void FoldCSSDoc(unsigned int startPos, int length, int, WordList *[], Accessor &styler) {
	bool foldComment = styler.GetPropertyInt("fold.comment") != 0;
	bool foldCompact = styler.GetPropertyInt("fold.compact", 1) != 0;
	unsigned int endPos = startPos + length;
	int visibleChars = 0;
	int lineCurrent = styler.GetLine(startPos);
	int levelPrev = styler.LevelAt(lineCurrent) & SC_FOLDLEVELNUMBERMASK;
	int levelCurrent = levelPrev;
	char chNext = styler[startPos];
	bool inComment = (styler.StyleAt(startPos-1) == SCE_CSS_COMMENT);
	for (unsigned int i = startPos; i < endPos; i++) {
		char ch = chNext;
		chNext = styler.SafeGetCharAt(i + 1);
		int style = styler.StyleAt(i);
		bool atEOL = (ch == '\r' && chNext != '\n') || (ch == '\n');
		if (foldComment) {
			if (!inComment && (style == SCE_CSS_COMMENT))
				levelCurrent++;
			else if (inComment && (style != SCE_CSS_COMMENT))
				levelCurrent--;
			inComment = (style == SCE_CSS_COMMENT);
		}
		if (style == SCE_CSS_OPERATOR) {
			if (ch == '{') {
				levelCurrent++;
			} else if (ch == '}') {
				levelCurrent--;
			}
		}
		if (atEOL) {
			int lev = levelPrev;
			if (visibleChars == 0 && foldCompact)
				lev |= SC_FOLDLEVELWHITEFLAG;
			if ((levelCurrent > levelPrev) && (visibleChars > 0))
				lev |= SC_FOLDLEVELHEADERFLAG;
			if (lev != styler.LevelAt(lineCurrent)) {
				styler.SetLevel(lineCurrent, lev);
			}
			lineCurrent++;
			levelPrev = levelCurrent;
			visibleChars = 0;
		}
		if (!isspacechar(ch))
			visibleChars++;
	}
	// Fill in the real level of the next line, keeping the current flags as they will be filled in later
	int flagsNext = styler.LevelAt(lineCurrent) & ~SC_FOLDLEVELNUMBERMASK;
	styler.SetLevel(lineCurrent, levelPrev | flagsNext);
}

static const char * const cssWordListDesc[] = {
	"Keywords",
	"Pseudo classes",
	0
};

LexerModule lmCss(SCLEX_CSS, ColouriseCssDoc, "css", FoldCSSDoc, cssWordListDesc);
<|endoftext|>


<commit_before>#include "libtiff.hh"

using namespace node;
using namespace v8;

Persistent<FunctionTemplate> TIFFFile::constructor_template;

namespace node {

  void TIFFFile::Initialize(Handle<Object> target) {
    HandleScope scope;

    Local<FunctionTemplate> t = FunctionTemplate::New(TIFFFile::New);
    constructor_template = Persistent<FunctionTemplate>::New(t);
    constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
    constructor_template->SetClassName(String::NewSymbol("TIFFFile"));

    constructor_template->InstanceTemplate()->
      SetAccessor(String::NewSymbol("IMAGEWIDTH"), TIFFFile::fieldsGetter);
    constructor_template->InstanceTemplate()->
      SetAccessor(String::NewSymbol("IMAGELENGTH"), TIFFFile::fieldsGetter);
    constructor_template->InstanceTemplate()->
      SetAccessor(String::NewSymbol("BITSPERSAMPLE"), TIFFFile::fieldsGetter);
    constructor_template->InstanceTemplate()->
      SetAccessor(String::NewSymbol("SAMPLESPERPIXEL"), TIFFFile::fieldsGetter);
    constructor_template->InstanceTemplate()->
      SetAccessor(String::NewSymbol("PLANARCONFIG"), TIFFFile::fieldsGetter);
    constructor_template->InstanceTemplate()->
      SetAccessor(String::NewSymbol("PHOTOMETRIC"), TIFFFile::fieldsGetter);
    constructor_template->InstanceTemplate()->
      SetAccessor(String::NewSymbol("ORIENTATION"), TIFFFile::fieldsGetter);
    constructor_template->InstanceTemplate()->
      SetAccessor(String::NewSymbol("scanlineSize"), TIFFFile::fieldsGetter);
    constructor_template->InstanceTemplate()->
      SetAccessor(String::NewSymbol("filename"), TIFFFile::fieldsGetter);

    NODE_SET_PROTOTYPE_METHOD(constructor_template, "pushAsPage", TIFFFile::pushAsPage);

    target->Set(String::NewSymbol("TIFFFile"), constructor_template->GetFunction());
  }

  Handle<Value> TIFFFile::New(const Arguments &args) {
    HandleScope scope;
    TIFFFile *tifffile;

    /* Validate input parameters */
    if (args.Length() == 2 && args[0]->IsString() && args[1]->IsString()) {
      String::Utf8Value filename(args[0]);
      String::Utf8Value mode(args[1]);

      /* Open tiff file */
      TIFF* tif = TIFFOpen(*filename, *mode);
      /* Check for success */
      if (tif != NULL) {
        /* Create TIFFFile object */
        tifffile = new TIFFFile(tif, *filename, (strcmp(*mode, "r") != 0));
      } else {
        /* Throw an error */
        return ThrowException(Exception::TypeError(String::New("Can't open tiff file.")));
      }
    } else {
      /* Throw an error */
      return ThrowException(Exception::TypeError(String::New("Invalid params (String filename, String mode)")));
    }
    /* Wrap object */
    tifffile->Wrap(args.This());
    /* Return new TIFFFile */
    return args.This();
  }

  Handle<Value> TIFFFile::fieldsGetter(Local< String > property, const AccessorInfo &info) {
        HandleScope scope;
        TIFFFile *self = ObjectWrap::Unwrap<TIFFFile>(info.This());

        String::Utf8Value propName(property);

        if (strcmp(*propName, "IMAGEWIDTH") == 0) {
          uint32 imageWidth;
          TIFFGetField(self->tif, TIFFTAG_IMAGEWIDTH, &imageWidth);
          return scope.Close(Uint32::New(imageWidth));
        } else if (strcmp(*propName, "IMAGELENGTH") == 0) {
          uint32 imageLength;
          TIFFGetField(self->tif, TIFFTAG_IMAGELENGTH, &imageLength);
          return scope.Close(Uint32::New(imageLength));
        } else if (strcmp(*propName, "BITSPERSAMPLE") == 0) {
          uint16 bps;
          TIFFGetField(self->tif, TIFFTAG_BITSPERSAMPLE, &bps);
          return scope.Close(Uint32::New(bps));
        } else if (strcmp(*propName, "SAMPLESPERPIXEL") == 0) {
          uint16 spp;
          TIFFGetField(self->tif, TIFFTAG_SAMPLESPERPIXEL, &spp);
          return scope.Close(Uint32::New(spp));
        } else if (strcmp(*propName, "PLANARCONFIG") == 0) {
          uint16 pc;
          TIFFGetField(self->tif, TIFFTAG_PLANARCONFIG, &pc);
          return scope.Close(Uint32::New(pc));
        } else if (strcmp(*propName, "PHOTOMETRIC") == 0) {
          uint16 pm;
          TIFFGetField(self->tif, TIFFTAG_PHOTOMETRIC, &pm);
          return scope.Close(Uint32::New(pm));
        } else if (strcmp(*propName, "ORIENTATION") == 0) {
          uint16 o9n;
          TIFFGetFieldDefaulted(self->tif, TIFFTAG_ORIENTATION, &o9n);
          return scope.Close(Uint32::New(o9n));
        } else if (strcmp(*propName, "scanlineSize") == 0) {
          int32 ss;
          ss = TIFFScanlineSize(self->tif);
          return scope.Close(Int32::New(ss));
        } else if (strcmp(*propName, "filename") == 0) {
          return scope.Close(String::New(self->filename));
        } else {
          return scope.Close(Undefined());
        }
  }

  Handle<Value> TIFFFile::pushAsPage(const Arguments &args) {
    HandleScope scope;
    TIFFFile *self = ObjectWrap::Unwrap<TIFFFile>(args.This());

    if (!self->forWrite) {
      return ThrowException(Exception::TypeError(String::New("Destination tiff must be opened for writing.")));
    }

    if (args.Length() != 1 || !TIFFFile::HasInstance(args[0])) {
      return ThrowException(Exception::TypeError(String::New("Invalid params (TIFFFile source)")));
    }
    TIFFFile *src = ObjectWrap::Unwrap<TIFFFile>(args[0]->ToObject());
    if (src->forWrite) {
      return ThrowException(Exception::TypeError(String::New("Source tiff must be opened for reading.")));
    }

    uint32 imageWidth, imageLength;
    uint16 bitsPerSample, samplesPerPixel, planarConfig, photometric, orientation;
    int32 scanlineSize;
    tdata_t buf;

    TIFFGetField(src->tif, TIFFTAG_IMAGEWIDTH, &imageWidth);
    TIFFGetField(src->tif, TIFFTAG_IMAGELENGTH, &imageLength);
    TIFFGetField(src->tif, TIFFTAG_BITSPERSAMPLE, &bitsPerSample);
    TIFFGetField(src->tif, TIFFTAG_SAMPLESPERPIXEL, &samplesPerPixel);
    TIFFGetField(src->tif, TIFFTAG_PLANARCONFIG, &planarConfig);
    TIFFGetField(src->tif, TIFFTAG_PHOTOMETRIC, &photometric);
    TIFFGetFieldDefaulted(src->tif, TIFFTAG_ORIENTATION, &orientation);
    scanlineSize = TIFFScanlineSize(src->tif);

    TIFFSetField(self->tif, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
    TIFFSetField(self->tif, TIFFTAG_IMAGEWIDTH, imageWidth);
    TIFFSetField(self->tif, TIFFTAG_IMAGELENGTH, imageLength);
    TIFFSetField(self->tif, TIFFTAG_BITSPERSAMPLE, bitsPerSample);
    TIFFSetField(self->tif, TIFFTAG_SAMPLESPERPIXEL, samplesPerPixel);
    TIFFSetField(self->tif, TIFFTAG_PLANARCONFIG, planarConfig);
    TIFFSetField(self->tif, TIFFTAG_PHOTOMETRIC, photometric);
    TIFFSetField(self->tif, TIFFTAG_ORIENTATION, orientation);
    TIFFSetField(self->tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE);
    TIFFSetField(self->tif, TIFFTAG_PAGENUMBER, self->pageNumber, self->pageNumber + 1);

    buf = _TIFFmalloc(scanlineSize);
    if (planarConfig == PLANARCONFIG_CONTIG) {
      for (uint32 i = 0; i < imageLength; i++) {
        TIFFReadScanline(src->tif, buf, i);
        TIFFWriteScanline(self->tif, buf, i);
      }
    } else if (planarConfig == PLANARCONFIG_SEPARATE) {
      for (uint16 s = 0; s < samplesPerPixel; s++) {
        for (uint32 i = 0; i < imageLength; i++) {
          TIFFReadScanline(self->tif, buf, i, s);
          TIFFWriteScanline(self->tif, buf, i, s);
        }
      }
      for (uint32 i = 0; i < imageLength; i++) {
        TIFFReadScanline(src->tif, buf, i, 0);
        TIFFWriteScanline(self->tif, buf, i, 0);
      }
    }
    _TIFFfree(buf);

    TIFFWriteDirectory(self->tif);
    self->pageNumber++;
    return args.This();
  }

}

// Exporting function
extern "C" void
init (v8::Handle<v8::Object> target)
{
    HandleScope scope;

    TIFFFile::Initialize(target);
}

NODE_MODULE(tiff_multipage, init);<commit_msg>Already have one captain..<commit_after>#include "libtiff.hh"

using namespace node;
using namespace v8;

Persistent<FunctionTemplate> TIFFFile::constructor_template;

namespace node {

  void TIFFFile::Initialize(Handle<Object> target) {
    HandleScope scope;

    Local<FunctionTemplate> t = FunctionTemplate::New(TIFFFile::New);
    constructor_template = Persistent<FunctionTemplate>::New(t);
    constructor_template->InstanceTemplate()->SetInternalFieldCount(1);
    constructor_template->SetClassName(String::NewSymbol("TIFFFile"));

    constructor_template->InstanceTemplate()->
      SetAccessor(String::NewSymbol("IMAGEWIDTH"), TIFFFile::fieldsGetter);
    constructor_template->InstanceTemplate()->
      SetAccessor(String::NewSymbol("IMAGELENGTH"), TIFFFile::fieldsGetter);
    constructor_template->InstanceTemplate()->
      SetAccessor(String::NewSymbol("BITSPERSAMPLE"), TIFFFile::fieldsGetter);
    constructor_template->InstanceTemplate()->
      SetAccessor(String::NewSymbol("SAMPLESPERPIXEL"), TIFFFile::fieldsGetter);
    constructor_template->InstanceTemplate()->
      SetAccessor(String::NewSymbol("PLANARCONFIG"), TIFFFile::fieldsGetter);
    constructor_template->InstanceTemplate()->
      SetAccessor(String::NewSymbol("PHOTOMETRIC"), TIFFFile::fieldsGetter);
    constructor_template->InstanceTemplate()->
      SetAccessor(String::NewSymbol("ORIENTATION"), TIFFFile::fieldsGetter);
    constructor_template->InstanceTemplate()->
      SetAccessor(String::NewSymbol("scanlineSize"), TIFFFile::fieldsGetter);
    constructor_template->InstanceTemplate()->
      SetAccessor(String::NewSymbol("filename"), TIFFFile::fieldsGetter);

    NODE_SET_PROTOTYPE_METHOD(constructor_template, "pushAsPage", TIFFFile::pushAsPage);

    target->Set(String::NewSymbol("TIFFFile"), constructor_template->GetFunction());
  }

  Handle<Value> TIFFFile::New(const Arguments &args) {
    HandleScope scope;
    TIFFFile *tifffile;

    if (args.Length() == 2 && args[0]->IsString() && args[1]->IsString()) {
      String::Utf8Value filename(args[0]);
      String::Utf8Value mode(args[1]);

      TIFF* tif = TIFFOpen(*filename, *mode);
      if (tif != NULL) {
        tifffile = new TIFFFile(tif, *filename, (strcmp(*mode, "r") != 0));
      } else {
        return ThrowException(Exception::TypeError(String::New("Can't open tiff file.")));
      }
    } else {
      return ThrowException(Exception::TypeError(String::New("Invalid params (String filename, String mode)")));
    }

    tifffile->Wrap(args.This());

    return args.This();
  }

  Handle<Value> TIFFFile::fieldsGetter(Local< String > property, const AccessorInfo &info) {
        HandleScope scope;
        TIFFFile *self = ObjectWrap::Unwrap<TIFFFile>(info.This());

        String::Utf8Value propName(property);

        if (strcmp(*propName, "IMAGEWIDTH") == 0) {
          uint32 imageWidth;
          TIFFGetField(self->tif, TIFFTAG_IMAGEWIDTH, &imageWidth);
          return scope.Close(Uint32::New(imageWidth));
        } else if (strcmp(*propName, "IMAGELENGTH") == 0) {
          uint32 imageLength;
          TIFFGetField(self->tif, TIFFTAG_IMAGELENGTH, &imageLength);
          return scope.Close(Uint32::New(imageLength));
        } else if (strcmp(*propName, "BITSPERSAMPLE") == 0) {
          uint16 bps;
          TIFFGetField(self->tif, TIFFTAG_BITSPERSAMPLE, &bps);
          return scope.Close(Uint32::New(bps));
        } else if (strcmp(*propName, "SAMPLESPERPIXEL") == 0) {
          uint16 spp;
          TIFFGetField(self->tif, TIFFTAG_SAMPLESPERPIXEL, &spp);
          return scope.Close(Uint32::New(spp));
        } else if (strcmp(*propName, "PLANARCONFIG") == 0) {
          uint16 pc;
          TIFFGetField(self->tif, TIFFTAG_PLANARCONFIG, &pc);
          return scope.Close(Uint32::New(pc));
        } else if (strcmp(*propName, "PHOTOMETRIC") == 0) {
          uint16 pm;
          TIFFGetField(self->tif, TIFFTAG_PHOTOMETRIC, &pm);
          return scope.Close(Uint32::New(pm));
        } else if (strcmp(*propName, "ORIENTATION") == 0) {
          uint16 o9n;
          TIFFGetFieldDefaulted(self->tif, TIFFTAG_ORIENTATION, &o9n);
          return scope.Close(Uint32::New(o9n));
        } else if (strcmp(*propName, "scanlineSize") == 0) {
          int32 ss;
          ss = TIFFScanlineSize(self->tif);
          return scope.Close(Int32::New(ss));
        } else if (strcmp(*propName, "filename") == 0) {
          return scope.Close(String::New(self->filename));
        } else {
          return scope.Close(Undefined());
        }
  }

  Handle<Value> TIFFFile::pushAsPage(const Arguments &args) {
    HandleScope scope;
    TIFFFile *self = ObjectWrap::Unwrap<TIFFFile>(args.This());

    if (!self->forWrite) {
      return ThrowException(Exception::TypeError(String::New("Destination tiff must be opened for writing.")));
    }

    if (args.Length() != 1 || !TIFFFile::HasInstance(args[0])) {
      return ThrowException(Exception::TypeError(String::New("Invalid params (TIFFFile source)")));
    }
    TIFFFile *src = ObjectWrap::Unwrap<TIFFFile>(args[0]->ToObject());
    if (src->forWrite) {
      return ThrowException(Exception::TypeError(String::New("Source tiff must be opened for reading.")));
    }

    uint32 imageWidth, imageLength;
    uint16 bitsPerSample, samplesPerPixel, planarConfig, photometric, orientation;
    int32 scanlineSize;
    tdata_t buf;

    TIFFGetField(src->tif, TIFFTAG_IMAGEWIDTH, &imageWidth);
    TIFFGetField(src->tif, TIFFTAG_IMAGELENGTH, &imageLength);
    TIFFGetField(src->tif, TIFFTAG_BITSPERSAMPLE, &bitsPerSample);
    TIFFGetField(src->tif, TIFFTAG_SAMPLESPERPIXEL, &samplesPerPixel);
    TIFFGetField(src->tif, TIFFTAG_PLANARCONFIG, &planarConfig);
    TIFFGetField(src->tif, TIFFTAG_PHOTOMETRIC, &photometric);
    TIFFGetFieldDefaulted(src->tif, TIFFTAG_ORIENTATION, &orientation);
    scanlineSize = TIFFScanlineSize(src->tif);

    TIFFSetField(self->tif, TIFFTAG_COMPRESSION, COMPRESSION_LZW);
    TIFFSetField(self->tif, TIFFTAG_IMAGEWIDTH, imageWidth);
    TIFFSetField(self->tif, TIFFTAG_IMAGELENGTH, imageLength);
    TIFFSetField(self->tif, TIFFTAG_BITSPERSAMPLE, bitsPerSample);
    TIFFSetField(self->tif, TIFFTAG_SAMPLESPERPIXEL, samplesPerPixel);
    TIFFSetField(self->tif, TIFFTAG_PLANARCONFIG, planarConfig);
    TIFFSetField(self->tif, TIFFTAG_PHOTOMETRIC, photometric);
    TIFFSetField(self->tif, TIFFTAG_ORIENTATION, orientation);
    TIFFSetField(self->tif, TIFFTAG_SUBFILETYPE, FILETYPE_PAGE);
    TIFFSetField(self->tif, TIFFTAG_PAGENUMBER, self->pageNumber, self->pageNumber + 1);

    buf = _TIFFmalloc(scanlineSize);
    if (planarConfig == PLANARCONFIG_CONTIG) {
      for (uint32 i = 0; i < imageLength; i++) {
        TIFFReadScanline(src->tif, buf, i);
        TIFFWriteScanline(self->tif, buf, i);
      }
    } else if (planarConfig == PLANARCONFIG_SEPARATE) {
      for (uint16 s = 0; s < samplesPerPixel; s++) {
        for (uint32 i = 0; i < imageLength; i++) {
          TIFFReadScanline(self->tif, buf, i, s);
          TIFFWriteScanline(self->tif, buf, i, s);
        }
      }
      for (uint32 i = 0; i < imageLength; i++) {
        TIFFReadScanline(src->tif, buf, i, 0);
        TIFFWriteScanline(self->tif, buf, i, 0);
      }
    }
    _TIFFfree(buf);

    TIFFWriteDirectory(self->tif);
    self->pageNumber++;
    return args.This();
  }

}

// Exporting function
extern "C" void
init (v8::Handle<v8::Object> target)
{
    HandleScope scope;

    TIFFFile::Initialize(target);
}

NODE_MODULE(tiff_multipage, init);<|endoftext|>


<commit_before>// Copyright (c) 2010 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 "chrome/browser/password_manager/password_form_data.h"
#include "chrome/browser/sync/sessions/session_state.h"
#include "chrome/test/live_sync/live_passwords_sync_test.h"

using webkit_glue::PasswordForm;

static const char* kValidPassphrase = "passphrase!";

// TODO(sync): Remove FAILS_ annotation after http://crbug.com/59867 is fixed.
#if defined(OS_MACOSX)
IN_PROC_BROWSER_TEST_F(TwoClientLivePasswordsSyncTest, FAILS_Add) {
#else
IN_PROC_BROWSER_TEST_F(TwoClientLivePasswordsSyncTest, Add) {
#endif
  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";

  PasswordForm form;
  form.origin = GURL("http://www.google.com/");
  form.username_value = ASCIIToUTF16("username");
  form.password_value = ASCIIToUTF16("password");

  AddLogin(GetVerifierPasswordStore(), form);
  AddLogin(GetPasswordStore(0), form);

  ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));

  std::vector<PasswordForm> expected;
  GetLogins(GetVerifierPasswordStore(), form, expected);
  ASSERT_EQ(1U, expected.size());

  std::vector<PasswordForm> actual_zero;
  GetLogins(GetPasswordStore(0), form, actual_zero);
  ASSERT_TRUE(ContainsSamePasswordForms(expected, actual_zero));

  std::vector<PasswordForm> actual_one;
  GetLogins(GetPasswordStore(1), form, actual_one);
  ASSERT_TRUE(ContainsSamePasswordForms(expected, actual_one));
}

// TODO(sync): Remove FAILS_ annotation after http://crbug.com/59867 is fixed.
#if defined(OS_MACOSX)
IN_PROC_BROWSER_TEST_F(TwoClientLivePasswordsSyncTest, FAILS_Race) {
#else
IN_PROC_BROWSER_TEST_F(TwoClientLivePasswordsSyncTest, Race) {
#endif
  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";

  PasswordForm form;
  form.origin = GURL("http://www.google.com/");

  PasswordForm form_zero;
  form_zero.origin = GURL("http://www.google.com/");
  form_zero.username_value = ASCIIToUTF16("username");
  form_zero.password_value = ASCIIToUTF16("zero");
  AddLogin(GetPasswordStore(0), form_zero);

  PasswordForm form_one;
  form_one.origin = GURL("http://www.google.com/");
  form_one.username_value = ASCIIToUTF16("username");
  form_one.password_value = ASCIIToUTF16("one");
  AddLogin(GetPasswordStore(1), form_one);

  ASSERT_TRUE(AwaitQuiescence());

  std::vector<PasswordForm> actual_zero;
  GetLogins(GetPasswordStore(0), form, actual_zero);
  ASSERT_EQ(1U, actual_zero.size());

  std::vector<PasswordForm> actual_one;
  GetLogins(GetPasswordStore(1), form, actual_one);
  ASSERT_EQ(1U, actual_one.size());

  ASSERT_TRUE(ContainsSamePasswordForms(actual_zero, actual_one));
}

// TODO(sync): Remove FAILS_ annotation after http://crbug.com/59867 is fixed.
#if defined(OS_MACOSX)
IN_PROC_BROWSER_TEST_F(TwoClientLivePasswordsSyncTest, FAILS_SetPassphrase) {
#else
IN_PROC_BROWSER_TEST_F(TwoClientLivePasswordsSyncTest, SetPassphrase) {
#endif
  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
  GetClient(0)->service()->SetPassphrase(kValidPassphrase, true);
  GetClient(0)->AwaitPassphraseAccepted();
  GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1));
  ASSERT_TRUE(GetClient(1)->service()->observed_passphrase_required());
  GetClient(1)->service()->SetPassphrase(kValidPassphrase, true);
  GetClient(1)->AwaitPassphraseAccepted();
  ASSERT_FALSE(GetClient(1)->service()->observed_passphrase_required());
}

// TODO(sync): Remove FAILS_ annotation after http://crbug.com/59867 is fixed.
#if defined(OS_MACOSX)
IN_PROC_BROWSER_TEST_F(TwoClientLivePasswordsSyncTest,
                       FAILS_SetPassphraseAndAddPassword) {
#else
IN_PROC_BROWSER_TEST_F(TwoClientLivePasswordsSyncTest,
                       SetPassphraseAndAddPassword) {
#endif
  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
  GetClient(0)->service()->SetPassphrase(kValidPassphrase, true);
  GetClient(0)->AwaitPassphraseAccepted();

  PasswordForm form;
  form.origin = GURL("http://www.google.com/");
  form.username_value = ASCIIToUTF16("username");
  form.password_value = ASCIIToUTF16("password");

  AddLogin(GetPasswordStore(0), form);

  GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1));
  ASSERT_TRUE(GetClient(1)->service()->observed_passphrase_required());
  ASSERT_EQ(1, GetClient(1)->GetLastSessionSnapshot()->
      num_conflicting_updates);

  GetClient(1)->service()->SetPassphrase(kValidPassphrase, true);
  GetClient(1)->AwaitPassphraseAccepted();
  ASSERT_FALSE(GetClient(1)->service()->observed_passphrase_required());
  GetClient(1)->AwaitSyncCycleCompletion("Accept passphrase and decrypt.");
  ASSERT_EQ(0, GetClient(1)->GetLastSessionSnapshot()->
      num_conflicting_updates);
}

// TODO(sync): Remove FAILS_ annotation after http://crbug.com/59867 is fixed.
#if defined(OS_MACOSX)
IN_PROC_BROWSER_TEST_F(TwoClientLivePasswordsSyncTest,
                       FAILS_SetPassphraseAndThenSetupSync) {
#else
IN_PROC_BROWSER_TEST_F(TwoClientLivePasswordsSyncTest,
                       SetPassphraseAndThenSetupSync) {
#endif
  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
  ASSERT_TRUE(GetClient(0)->SetupSync());
  GetClient(0)->service()->SetPassphrase(kValidPassphrase, true);
  GetClient(0)->AwaitPassphraseAccepted();
  GetClient(0)->AwaitSyncCycleCompletion("Initial sync.");

  ASSERT_TRUE(GetClient(1)->SetupSync());
  ASSERT_TRUE(AwaitQuiescence());
  ASSERT_TRUE(GetClient(1)->service()->observed_passphrase_required());
  GetClient(1)->service()->SetPassphrase(kValidPassphrase, true);
  GetClient(1)->AwaitPassphraseAccepted();
  ASSERT_FALSE(GetClient(1)->service()->observed_passphrase_required());
}

// TODO(sync): Remove FAILS_ annotation after http://crbug.com/59867 is fixed.
#if defined(OS_MACOSX)
IN_PROC_BROWSER_TEST_F(TwoClientLivePasswordsSyncTest,
                       FAILS_SetPassphraseTwice) {
#else
IN_PROC_BROWSER_TEST_F(TwoClientLivePasswordsSyncTest,
                       SetPassphraseTwice) {
#endif
  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";

  GetClient(0)->service()->SetPassphrase(kValidPassphrase, true);
  GetClient(0)->AwaitPassphraseAccepted();
  GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1));
  ASSERT_TRUE(GetClient(1)->service()->observed_passphrase_required());

  GetClient(1)->service()->SetPassphrase(kValidPassphrase, true);
  GetClient(1)->AwaitPassphraseAccepted();
  ASSERT_FALSE(GetClient(1)->service()->observed_passphrase_required());

  GetClient(1)->service()->SetPassphrase(kValidPassphrase, true);
  GetClient(1)->AwaitPassphraseAccepted();
  ASSERT_FALSE(GetClient(1)->service()->observed_passphrase_required());
}
<commit_msg>Disabling a couple of failing passphrase sync tests.<commit_after>// Copyright (c) 2010 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 "chrome/browser/password_manager/password_form_data.h"
#include "chrome/browser/sync/sessions/session_state.h"
#include "chrome/test/live_sync/live_passwords_sync_test.h"

using webkit_glue::PasswordForm;

static const char* kValidPassphrase = "passphrase!";

// TODO(sync): Remove FAILS_ annotation after http://crbug.com/59867 is fixed.
#if defined(OS_MACOSX)
IN_PROC_BROWSER_TEST_F(TwoClientLivePasswordsSyncTest, FAILS_Add) {
#else
IN_PROC_BROWSER_TEST_F(TwoClientLivePasswordsSyncTest, Add) {
#endif
  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";

  PasswordForm form;
  form.origin = GURL("http://www.google.com/");
  form.username_value = ASCIIToUTF16("username");
  form.password_value = ASCIIToUTF16("password");

  AddLogin(GetVerifierPasswordStore(), form);
  AddLogin(GetPasswordStore(0), form);

  ASSERT_TRUE(GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1)));

  std::vector<PasswordForm> expected;
  GetLogins(GetVerifierPasswordStore(), form, expected);
  ASSERT_EQ(1U, expected.size());

  std::vector<PasswordForm> actual_zero;
  GetLogins(GetPasswordStore(0), form, actual_zero);
  ASSERT_TRUE(ContainsSamePasswordForms(expected, actual_zero));

  std::vector<PasswordForm> actual_one;
  GetLogins(GetPasswordStore(1), form, actual_one);
  ASSERT_TRUE(ContainsSamePasswordForms(expected, actual_one));
}

// TODO(sync): Remove FAILS_ annotation after http://crbug.com/59867 is fixed.
#if defined(OS_MACOSX)
IN_PROC_BROWSER_TEST_F(TwoClientLivePasswordsSyncTest, FAILS_Race) {
#else
IN_PROC_BROWSER_TEST_F(TwoClientLivePasswordsSyncTest, Race) {
#endif
  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";

  PasswordForm form;
  form.origin = GURL("http://www.google.com/");

  PasswordForm form_zero;
  form_zero.origin = GURL("http://www.google.com/");
  form_zero.username_value = ASCIIToUTF16("username");
  form_zero.password_value = ASCIIToUTF16("zero");
  AddLogin(GetPasswordStore(0), form_zero);

  PasswordForm form_one;
  form_one.origin = GURL("http://www.google.com/");
  form_one.username_value = ASCIIToUTF16("username");
  form_one.password_value = ASCIIToUTF16("one");
  AddLogin(GetPasswordStore(1), form_one);

  ASSERT_TRUE(AwaitQuiescence());

  std::vector<PasswordForm> actual_zero;
  GetLogins(GetPasswordStore(0), form, actual_zero);
  ASSERT_EQ(1U, actual_zero.size());

  std::vector<PasswordForm> actual_one;
  GetLogins(GetPasswordStore(1), form, actual_one);
  ASSERT_EQ(1U, actual_one.size());

  ASSERT_TRUE(ContainsSamePasswordForms(actual_zero, actual_one));
}

// TODO(sync): Remove FAILS_ annotation after http://crbug.com/59867 is fixed.
#if defined(OS_MACOSX)
IN_PROC_BROWSER_TEST_F(TwoClientLivePasswordsSyncTest, FAILS_SetPassphrase) {
#else
IN_PROC_BROWSER_TEST_F(TwoClientLivePasswordsSyncTest, SetPassphrase) {
#endif
  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
  GetClient(0)->service()->SetPassphrase(kValidPassphrase, true);
  GetClient(0)->AwaitPassphraseAccepted();
  GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1));
  ASSERT_TRUE(GetClient(1)->service()->observed_passphrase_required());
  GetClient(1)->service()->SetPassphrase(kValidPassphrase, true);
  GetClient(1)->AwaitPassphraseAccepted();
  ASSERT_FALSE(GetClient(1)->service()->observed_passphrase_required());
}

// TODO(sync): Remove FAILS_ annotation after http://crbug.com/59867 is fixed.
#if defined(OS_MACOSX)
IN_PROC_BROWSER_TEST_F(TwoClientLivePasswordsSyncTest,
                       FAILS_SetPassphraseAndAddPassword) {
#else
IN_PROC_BROWSER_TEST_F(TwoClientLivePasswordsSyncTest,
                       SetPassphraseAndAddPassword) {
#endif
  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";
  GetClient(0)->service()->SetPassphrase(kValidPassphrase, true);
  GetClient(0)->AwaitPassphraseAccepted();

  PasswordForm form;
  form.origin = GURL("http://www.google.com/");
  form.username_value = ASCIIToUTF16("username");
  form.password_value = ASCIIToUTF16("password");

  AddLogin(GetPasswordStore(0), form);

  GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1));
  ASSERT_TRUE(GetClient(1)->service()->observed_passphrase_required());
  ASSERT_EQ(1, GetClient(1)->GetLastSessionSnapshot()->
      num_conflicting_updates);

  GetClient(1)->service()->SetPassphrase(kValidPassphrase, true);
  GetClient(1)->AwaitPassphraseAccepted();
  ASSERT_FALSE(GetClient(1)->service()->observed_passphrase_required());
  GetClient(1)->AwaitSyncCycleCompletion("Accept passphrase and decrypt.");
  ASSERT_EQ(0, GetClient(1)->GetLastSessionSnapshot()->
      num_conflicting_updates);
}

// TODO(sync): Remove DISABLED_ annotation after http://crbug.com/59867 and
// http://crbug.com/67862 are fixed.
IN_PROC_BROWSER_TEST_F(TwoClientLivePasswordsSyncTest,
                       DISABLED_SetPassphraseAndThenSetupSync) {
  ASSERT_TRUE(SetupClients()) << "SetupClients() failed.";
  ASSERT_TRUE(GetClient(0)->SetupSync());
  GetClient(0)->service()->SetPassphrase(kValidPassphrase, true);
  GetClient(0)->AwaitPassphraseAccepted();
  GetClient(0)->AwaitSyncCycleCompletion("Initial sync.");

  ASSERT_TRUE(GetClient(1)->SetupSync());
  ASSERT_TRUE(AwaitQuiescence());
  ASSERT_TRUE(GetClient(1)->service()->observed_passphrase_required());
  GetClient(1)->service()->SetPassphrase(kValidPassphrase, true);
  GetClient(1)->AwaitPassphraseAccepted();
  ASSERT_FALSE(GetClient(1)->service()->observed_passphrase_required());
}

// TODO(sync): Remove DISABLED_ annotation after http://crbug.com/59867 and
// http://crbug.com/67862 are fixed.
IN_PROC_BROWSER_TEST_F(TwoClientLivePasswordsSyncTest,
                       DISABLED_SetPassphraseTwice) {
  ASSERT_TRUE(SetupSync()) << "SetupSync() failed.";

  GetClient(0)->service()->SetPassphrase(kValidPassphrase, true);
  GetClient(0)->AwaitPassphraseAccepted();
  GetClient(0)->AwaitMutualSyncCycleCompletion(GetClient(1));
  ASSERT_TRUE(GetClient(1)->service()->observed_passphrase_required());

  GetClient(1)->service()->SetPassphrase(kValidPassphrase, true);
  GetClient(1)->AwaitPassphraseAccepted();
  ASSERT_FALSE(GetClient(1)->service()->observed_passphrase_required());

  GetClient(1)->service()->SetPassphrase(kValidPassphrase, true);
  GetClient(1)->AwaitPassphraseAccepted();
  ASSERT_FALSE(GetClient(1)->service()->observed_passphrase_required());
}
<|endoftext|>


<commit_before>///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Lewis Baker
// Licenced under MIT license. See LICENSE.txt for details.
///////////////////////////////////////////////////////////////////////////////
#ifndef CPPCORO_DETAIL_WIN32_OVERLAPPED_OPERATION_HPP_INCLUDED
#define CPPCORO_DETAIL_WIN32_OVERLAPPED_OPERATION_HPP_INCLUDED

#include <cppcoro/cancellation_registration.hpp>
#include <cppcoro/cancellation_token.hpp>
#include <cppcoro/operation_cancelled.hpp>

#include <cppcoro/detail/win32.hpp>

#include <optional>
#include <system_error>
#include <experimental/coroutine>
#include <cassert>

namespace cppcoro
{
	namespace detail
	{
		class win32_overlapped_operation_base
			: protected detail::win32::io_state
		{
		public:

			win32_overlapped_operation_base(
				detail::win32::io_state::callback_type* callback) noexcept
				: detail::win32::io_state(callback)
				, m_errorCode(0)
				, m_numberOfBytesTransferred(0)
			{}

			win32_overlapped_operation_base(
				void* pointer,
				detail::win32::io_state::callback_type* callback) noexcept
				: detail::win32::io_state(pointer, callback)
				, m_errorCode(0)
				, m_numberOfBytesTransferred(0)
			{}

			win32_overlapped_operation_base(
				std::uint64_t offset,
				detail::win32::io_state::callback_type* callback) noexcept
				: detail::win32::io_state(offset, callback)
				, m_errorCode(0)
				, m_numberOfBytesTransferred(0)
			{}

			_OVERLAPPED* get_overlapped() noexcept
			{
				return reinterpret_cast<_OVERLAPPED*>(
					static_cast<detail::win32::overlapped*>(this));
			}

			std::size_t get_result()
			{
				if (m_errorCode != 0)
				{
					throw std::system_error{
						static_cast<int>(m_errorCode),
						std::system_category()
					};
				}

				return m_numberOfBytesTransferred;
			}

			detail::win32::dword_t m_errorCode;
			detail::win32::dword_t m_numberOfBytesTransferred;

		};

		template<typename OPERATION>
		class win32_overlapped_operation
			: protected win32_overlapped_operation_base
		{
		protected:

			win32_overlapped_operation() noexcept
				: win32_overlapped_operation_base(
					&win32_overlapped_operation::on_operation_completed)
			{}

			win32_overlapped_operation(void* pointer) noexcept
				: win32_overlapped_operation_base(
					pointer,
					&win32_overlapped_operation::on_operation_completed)
			{}

			win32_overlapped_operation(std::uint64_t offset) noexcept
				: win32_overlapped_operation_base(
					offset,
					&win32_overlapped_operation::on_operation_completed)
			{}

		public:

			bool await_ready() const noexcept { return false; }

			bool await_suspend(std::experimental::coroutine_handle<> awaitingCoroutine)
			{
				static_assert(std::is_base_of_v<win32_overlapped_operation, OPERATION>);

				m_awaitingCoroutine = awaitingCoroutine;
				return static_cast<OPERATION*>(this)->try_start();
			}

			decltype(auto) await_resume()
			{
				return static_cast<OPERATION*>(this)->get_result();
			}

		private:

			static void on_operation_completed(
				detail::win32::io_state* ioState,
				detail::win32::dword_t errorCode,
				detail::win32::dword_t numberOfBytesTransferred,
				[[maybe_unused]] detail::win32::ulongptr_t completionKey) noexcept
			{
				auto* operation = static_cast<win32_overlapped_operation*>(ioState);
				operation->m_errorCode = errorCode;
				operation->m_numberOfBytesTransferred = numberOfBytesTransferred;
				operation->m_awaitingCoroutine.resume();
			}

			std::experimental::coroutine_handle<> m_awaitingCoroutine;

		};

		template<typename OPERATION>
		class win32_overlapped_operation_cancellable
			: protected win32_overlapped_operation_base
		{
			// ERROR_OPERATION_ABORTED value from <Windows.h>
			static constexpr detail::win32::dword_t error_operation_aborted = 995L;

		protected:

			win32_overlapped_operation_cancellable(cancellation_token&& ct) noexcept
				: win32_overlapped_operation_base(&win32_overlapped_operation_cancellable::on_operation_completed)
				, m_state(ct.is_cancellation_requested() ? state::completed : state::not_started)
				, m_cancellationToken(std::move(ct))
			{
				m_errorCode = error_operation_aborted;
			}

			win32_overlapped_operation_cancellable(
				void* pointer,
				cancellation_token&& ct) noexcept
				: win32_overlapped_operation_base(pointer, &win32_overlapped_operation_cancellable::on_operation_completed)
				, m_state(ct.is_cancellation_requested() ? state::completed : state::not_started)
				, m_cancellationToken(std::move(ct))
			{
				m_errorCode = error_operation_aborted;
			}

			win32_overlapped_operation_cancellable(
				std::uint64_t offset,
				cancellation_token&& ct) noexcept
				: win32_overlapped_operation_base(offset, &win32_overlapped_operation_cancellable::on_operation_completed)
				, m_state(ct.is_cancellation_requested() ? state::completed : state::not_started)
				, m_cancellationToken(std::move(ct))
			{
				m_errorCode = error_operation_aborted;
			}

			win32_overlapped_operation_cancellable(
				win32_overlapped_operation_cancellable&& other) noexcept
				: win32_overlapped_operation_base(std::move(other))
				, m_state(other.m_state.load(std::memory_order_relaxed))
				, m_cancellationToken(std::move(other.m_cancellationToken))
			{
				assert(m_errorCode == other.m_errorCode);
				assert(m_numberOfBytesTransferred == other.m_numberOfBytesTransferred);
			}

		public:

			bool await_ready() const noexcept
			{
				return m_state.load(std::memory_order_relaxed) == state::completed;
			}

			bool await_suspend(std::experimental::coroutine_handle<> awaitingCoroutine)
			{
				static_assert(std::is_base_of_v<win32_overlapped_operation_cancellable, OPERATION>);

				m_awaitingCoroutine = awaitingCoroutine;

				// TRICKY: Register cancellation callback before starting the operation
				// in case the callback registration throws due to insufficient
				// memory. We need to make sure that the logic that occurs after
				// starting the operation is noexcept, otherwise we run into the
				// problem of not being able to cancel the started operation and
				// the dilemma of what to do with the exception.
				//
				// However, doing this means that the cancellation callback may run
				// prior to returning below so in the case that cancellation may
				// occur we defer setting the state to 'started' until after
				// the operation has finished starting. The cancellation callback
				// will only attempt to request cancellation of the operation with
				// CancelIoEx() once the state has been set to 'started'.
				const bool canBeCancelled = m_cancellationToken.can_be_cancelled();
				if (canBeCancelled)
				{
					m_cancellationCallback.emplace(
						std::move(m_cancellationToken),
						[this] { this->on_cancellation_requested(); });
				}
				else
				{
					m_state.store(state::started, std::memory_order_relaxed);
				}

				// Now start the operation.
				const bool willCompleteAsynchronously = static_cast<OPERATION*>(this)->try_start();
				if (!willCompleteAsynchronously)
				{
					// Operation completed synchronously, resume awaiting coroutine immediately.
					return false;
				}

				if (canBeCancelled)
				{
					// Need to flag that the operation has finished starting now.

					// However, the operation may have completed concurrently on
					// another thread, transitioning directly from not_started -> complete.
					// Or it may have had the cancellation callback execute and transition
					// from not_started -> cancellation_requested. We use a compare-exchange
					// to determine a winner between these potential racing cases.
					state oldState = state::not_started;
					if (!m_state.compare_exchange_strong(
						oldState,
						state::started,
						std::memory_order_release,
						std::memory_order_acquire))
					{
						if (oldState == state::cancellation_requested)
						{
							// Request the operation be cancelled.
							// Note that it may have already completed on a background
							// thread by now so this request for cancellation may end up
							// being ignored.
							static_cast<OPERATION*>(this)->cancel();

							if (!m_state.compare_exchange_strong(
								oldState,
								state::started,
								std::memory_order_release,
								std::memory_order_acquire))
							{
								assert(oldState == state::completed);
								return false;
							}
						}
						else
						{
							assert(oldState == state::completed);
							return false;
						}
					}
				}

				return true;
			}

			decltype(auto) await_resume()
			{
				// Free memory used by the cancellation callback now that the operation
				// has completed rather than waiting until the operation object destructs.
				// eg. If the operation is passed to when_all() then the operation object
				// may not be destructed until all of the operations complete.
				m_cancellationCallback.reset();

				if (m_errorCode == error_operation_aborted)
				{
					throw operation_cancelled{};
				}

				return static_cast<OPERATION*>(this)->get_result();
			}

		private:

			enum class state
			{
				not_started,
				started,
				cancellation_requested,
				completed
			};

			void on_cancellation_requested() noexcept
			{
				auto oldState = m_state.load(std::memory_order_acquire);
				if (oldState == state::not_started)
				{
					// This callback is running concurrently with await_suspend().
					// The call to start the operation may not have returned yet so
					// we can't safely request cancellation of it. Instead we try to
					// notify the await_suspend() thread by transitioning the state
					// to state::cancellation_requested so that the await_suspend()
					// thread can request cancellation after it has finished starting
					// the operation.
					const bool transferredCancelResponsibility =
						m_state.compare_exchange_strong(
							oldState,
							state::cancellation_requested,
							std::memory_order_release,
							std::memory_order_acquire);
					if (transferredCancelResponsibility)
					{
						return;
					}
				}

				// No point requesting cancellation if the operation has already completed.
				if (oldState != state::completed)
				{
					static_cast<OPERATION*>(this)->cancel();
				}
			}

			static void on_operation_completed(
				detail::win32::io_state* ioState,
				detail::win32::dword_t errorCode,
				detail::win32::dword_t numberOfBytesTransferred,
				[[maybe_unused]] detail::win32::ulongptr_t completionKey) noexcept
			{
				auto* operation = static_cast<win32_overlapped_operation_cancellable*>(ioState);

				operation->m_errorCode = errorCode;
				operation->m_numberOfBytesTransferred = numberOfBytesTransferred;

				auto state = operation->m_state.load(std::memory_order_acquire);
				if (state == state::started)
				{
					operation->m_state.store(state::completed, std::memory_order_relaxed);
					operation->m_awaitingCoroutine.resume();
				}
				else
				{
					// We are racing with await_suspend() call suspending.
					// Try to mark it as completed using an atomic exchange and look
					// at the previous value to determine whether the coroutine suspended
					// first (in which case we resume it now) or we marked it as completed
					// first (in which case await_suspend() will return false and immediately
					// resume the coroutine).
					state = operation->m_state.exchange(
						state::completed,
						std::memory_order_acq_rel);
					if (state == state::started)
					{
						// The await_suspend() method returned (or will return) 'true' and so
						// we need to resume the coroutine.
						operation->m_awaitingCoroutine.resume();
					}
				}
			}

			std::atomic<state> m_state;
			cppcoro::cancellation_token m_cancellationToken;
			std::optional<cppcoro::cancellation_registration> m_cancellationCallback;
			std::experimental::coroutine_handle<> m_awaitingCoroutine;

		};
	}
}

#endif
<commit_msg>Work around MSVC codegen bug that caused socket tests to hang<commit_after>///////////////////////////////////////////////////////////////////////////////
// Copyright (c) Lewis Baker
// Licenced under MIT license. See LICENSE.txt for details.
///////////////////////////////////////////////////////////////////////////////
#ifndef CPPCORO_DETAIL_WIN32_OVERLAPPED_OPERATION_HPP_INCLUDED
#define CPPCORO_DETAIL_WIN32_OVERLAPPED_OPERATION_HPP_INCLUDED

#include <cppcoro/cancellation_registration.hpp>
#include <cppcoro/cancellation_token.hpp>
#include <cppcoro/operation_cancelled.hpp>

#include <cppcoro/detail/win32.hpp>

#include <optional>
#include <system_error>
#include <experimental/coroutine>
#include <cassert>

namespace cppcoro
{
	namespace detail
	{
		class win32_overlapped_operation_base
			: protected detail::win32::io_state
		{
		public:

			win32_overlapped_operation_base(
				detail::win32::io_state::callback_type* callback) noexcept
				: detail::win32::io_state(callback)
				, m_errorCode(0)
				, m_numberOfBytesTransferred(0)
			{}

			win32_overlapped_operation_base(
				void* pointer,
				detail::win32::io_state::callback_type* callback) noexcept
				: detail::win32::io_state(pointer, callback)
				, m_errorCode(0)
				, m_numberOfBytesTransferred(0)
			{}

			win32_overlapped_operation_base(
				std::uint64_t offset,
				detail::win32::io_state::callback_type* callback) noexcept
				: detail::win32::io_state(offset, callback)
				, m_errorCode(0)
				, m_numberOfBytesTransferred(0)
			{}

			_OVERLAPPED* get_overlapped() noexcept
			{
				return reinterpret_cast<_OVERLAPPED*>(
					static_cast<detail::win32::overlapped*>(this));
			}

			std::size_t get_result()
			{
				if (m_errorCode != 0)
				{
					throw std::system_error{
						static_cast<int>(m_errorCode),
						std::system_category()
					};
				}

				return m_numberOfBytesTransferred;
			}

			detail::win32::dword_t m_errorCode;
			detail::win32::dword_t m_numberOfBytesTransferred;

		};

		template<typename OPERATION>
		class win32_overlapped_operation
			: protected win32_overlapped_operation_base
		{
		protected:

			win32_overlapped_operation() noexcept
				: win32_overlapped_operation_base(
					&win32_overlapped_operation::on_operation_completed)
			{}

			win32_overlapped_operation(void* pointer) noexcept
				: win32_overlapped_operation_base(
					pointer,
					&win32_overlapped_operation::on_operation_completed)
			{}

			win32_overlapped_operation(std::uint64_t offset) noexcept
				: win32_overlapped_operation_base(
					offset,
					&win32_overlapped_operation::on_operation_completed)
			{}

		public:

			bool await_ready() const noexcept { return false; }

			CPPCORO_NOINLINE
			bool await_suspend(std::experimental::coroutine_handle<> awaitingCoroutine)
			{
				static_assert(std::is_base_of_v<win32_overlapped_operation, OPERATION>);

				m_awaitingCoroutine = awaitingCoroutine;
				return static_cast<OPERATION*>(this)->try_start();
			}

			decltype(auto) await_resume()
			{
				return static_cast<OPERATION*>(this)->get_result();
			}

		private:

			static void on_operation_completed(
				detail::win32::io_state* ioState,
				detail::win32::dword_t errorCode,
				detail::win32::dword_t numberOfBytesTransferred,
				[[maybe_unused]] detail::win32::ulongptr_t completionKey) noexcept
			{
				auto* operation = static_cast<win32_overlapped_operation*>(ioState);
				operation->m_errorCode = errorCode;
				operation->m_numberOfBytesTransferred = numberOfBytesTransferred;
				operation->m_awaitingCoroutine.resume();
			}

			std::experimental::coroutine_handle<> m_awaitingCoroutine;

		};

		template<typename OPERATION>
		class win32_overlapped_operation_cancellable
			: protected win32_overlapped_operation_base
		{
			// ERROR_OPERATION_ABORTED value from <Windows.h>
			static constexpr detail::win32::dword_t error_operation_aborted = 995L;

		protected:

			win32_overlapped_operation_cancellable(cancellation_token&& ct) noexcept
				: win32_overlapped_operation_base(&win32_overlapped_operation_cancellable::on_operation_completed)
				, m_state(ct.is_cancellation_requested() ? state::completed : state::not_started)
				, m_cancellationToken(std::move(ct))
			{
				m_errorCode = error_operation_aborted;
			}

			win32_overlapped_operation_cancellable(
				void* pointer,
				cancellation_token&& ct) noexcept
				: win32_overlapped_operation_base(pointer, &win32_overlapped_operation_cancellable::on_operation_completed)
				, m_state(ct.is_cancellation_requested() ? state::completed : state::not_started)
				, m_cancellationToken(std::move(ct))
			{
				m_errorCode = error_operation_aborted;
			}

			win32_overlapped_operation_cancellable(
				std::uint64_t offset,
				cancellation_token&& ct) noexcept
				: win32_overlapped_operation_base(offset, &win32_overlapped_operation_cancellable::on_operation_completed)
				, m_state(ct.is_cancellation_requested() ? state::completed : state::not_started)
				, m_cancellationToken(std::move(ct))
			{
				m_errorCode = error_operation_aborted;
			}

			win32_overlapped_operation_cancellable(
				win32_overlapped_operation_cancellable&& other) noexcept
				: win32_overlapped_operation_base(std::move(other))
				, m_state(other.m_state.load(std::memory_order_relaxed))
				, m_cancellationToken(std::move(other.m_cancellationToken))
			{
				assert(m_errorCode == other.m_errorCode);
				assert(m_numberOfBytesTransferred == other.m_numberOfBytesTransferred);
			}

		public:

			bool await_ready() const noexcept
			{
				return m_state.load(std::memory_order_relaxed) == state::completed;
			}

			CPPCORO_NOINLINE
			bool await_suspend(std::experimental::coroutine_handle<> awaitingCoroutine)
			{
				static_assert(std::is_base_of_v<win32_overlapped_operation_cancellable, OPERATION>);

				m_awaitingCoroutine = awaitingCoroutine;

				// TRICKY: Register cancellation callback before starting the operation
				// in case the callback registration throws due to insufficient
				// memory. We need to make sure that the logic that occurs after
				// starting the operation is noexcept, otherwise we run into the
				// problem of not being able to cancel the started operation and
				// the dilemma of what to do with the exception.
				//
				// However, doing this means that the cancellation callback may run
				// prior to returning below so in the case that cancellation may
				// occur we defer setting the state to 'started' until after
				// the operation has finished starting. The cancellation callback
				// will only attempt to request cancellation of the operation with
				// CancelIoEx() once the state has been set to 'started'.
				const bool canBeCancelled = m_cancellationToken.can_be_cancelled();
				if (canBeCancelled)
				{
					m_cancellationCallback.emplace(
						std::move(m_cancellationToken),
						[this] { this->on_cancellation_requested(); });
				}
				else
				{
					m_state.store(state::started, std::memory_order_relaxed);
				}

				// Now start the operation.
				const bool willCompleteAsynchronously = static_cast<OPERATION*>(this)->try_start();
				if (!willCompleteAsynchronously)
				{
					// Operation completed synchronously, resume awaiting coroutine immediately.
					return false;
				}

				if (canBeCancelled)
				{
					// Need to flag that the operation has finished starting now.

					// However, the operation may have completed concurrently on
					// another thread, transitioning directly from not_started -> complete.
					// Or it may have had the cancellation callback execute and transition
					// from not_started -> cancellation_requested. We use a compare-exchange
					// to determine a winner between these potential racing cases.
					state oldState = state::not_started;
					if (!m_state.compare_exchange_strong(
						oldState,
						state::started,
						std::memory_order_release,
						std::memory_order_acquire))
					{
						if (oldState == state::cancellation_requested)
						{
							// Request the operation be cancelled.
							// Note that it may have already completed on a background
							// thread by now so this request for cancellation may end up
							// being ignored.
							static_cast<OPERATION*>(this)->cancel();

							if (!m_state.compare_exchange_strong(
								oldState,
								state::started,
								std::memory_order_release,
								std::memory_order_acquire))
							{
								assert(oldState == state::completed);
								return false;
							}
						}
						else
						{
							assert(oldState == state::completed);
							return false;
						}
					}
				}

				return true;
			}

			decltype(auto) await_resume()
			{
				// Free memory used by the cancellation callback now that the operation
				// has completed rather than waiting until the operation object destructs.
				// eg. If the operation is passed to when_all() then the operation object
				// may not be destructed until all of the operations complete.
				m_cancellationCallback.reset();

				if (m_errorCode == error_operation_aborted)
				{
					throw operation_cancelled{};
				}

				return static_cast<OPERATION*>(this)->get_result();
			}

		private:

			enum class state
			{
				not_started,
				started,
				cancellation_requested,
				completed
			};

			void on_cancellation_requested() noexcept
			{
				auto oldState = m_state.load(std::memory_order_acquire);
				if (oldState == state::not_started)
				{
					// This callback is running concurrently with await_suspend().
					// The call to start the operation may not have returned yet so
					// we can't safely request cancellation of it. Instead we try to
					// notify the await_suspend() thread by transitioning the state
					// to state::cancellation_requested so that the await_suspend()
					// thread can request cancellation after it has finished starting
					// the operation.
					const bool transferredCancelResponsibility =
						m_state.compare_exchange_strong(
							oldState,
							state::cancellation_requested,
							std::memory_order_release,
							std::memory_order_acquire);
					if (transferredCancelResponsibility)
					{
						return;
					}
				}

				// No point requesting cancellation if the operation has already completed.
				if (oldState != state::completed)
				{
					static_cast<OPERATION*>(this)->cancel();
				}
			}

			static void on_operation_completed(
				detail::win32::io_state* ioState,
				detail::win32::dword_t errorCode,
				detail::win32::dword_t numberOfBytesTransferred,
				[[maybe_unused]] detail::win32::ulongptr_t completionKey) noexcept
			{
				auto* operation = static_cast<win32_overlapped_operation_cancellable*>(ioState);

				operation->m_errorCode = errorCode;
				operation->m_numberOfBytesTransferred = numberOfBytesTransferred;

				auto state = operation->m_state.load(std::memory_order_acquire);
				if (state == state::started)
				{
					operation->m_state.store(state::completed, std::memory_order_relaxed);
					operation->m_awaitingCoroutine.resume();
				}
				else
				{
					// We are racing with await_suspend() call suspending.
					// Try to mark it as completed using an atomic exchange and look
					// at the previous value to determine whether the coroutine suspended
					// first (in which case we resume it now) or we marked it as completed
					// first (in which case await_suspend() will return false and immediately
					// resume the coroutine).
					state = operation->m_state.exchange(
						state::completed,
						std::memory_order_acq_rel);
					if (state == state::started)
					{
						// The await_suspend() method returned (or will return) 'true' and so
						// we need to resume the coroutine.
						operation->m_awaitingCoroutine.resume();
					}
				}
			}

			std::atomic<state> m_state;
			cppcoro::cancellation_token m_cancellationToken;
			std::optional<cppcoro::cancellation_registration> m_cancellationCallback;
			std::experimental::coroutine_handle<> m_awaitingCoroutine;

		};
	}
}

#endif
<|endoftext|>


<commit_before>/**
 * @file	src/Module.cpp
 * @date	dec. 2015
 * @author	PhRG - opticalp.fr
 */

/*
 Copyright (c) 2015 Ph. Renaud-Goud / Opticalp

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 */

#include "Module.h"
#include "ModuleFactory.h"
#include "ModuleManager.h"
#include "ThreadManager.h"
#include "ModuleTask.h"

#include "OutPort.h"

#include "Poco/NumberFormatter.h"
#include "Poco/NumberParser.h"

std::vector<std::string> Module::names;
Poco::RWLock Module::namesLock;

void Module::notifyCreation()
{
    // if not EmptyModule, add this to module manager
    if (mParent)
        Poco::Util::Application::instance().getSubsystem<ModuleManager>().addModule(this);
}

Module::~Module()
{
	// TODO: tasks?

    // notify parent factory
    if (mParent)
    {
        mParent->removeChildModule(this);

        // notify module manager
        Poco::Util::Application::instance().getSubsystem<ModuleManager>().removeModule(this);
    }
}

#include "Poco/Exception.h"

void Module::setInternalName(std::string internalName)
{
    namesLock.writeLock();

    switch (checkName(internalName))
    {
    case nameOk:
        mInternalName = internalName;
        names.push_back(mInternalName);
        namesLock.unlock();
        return;
    case nameExists:
        namesLock.unlock();
        throw Poco::ExistsException("setInternalName",
                internalName + " already in use");
    case nameBadSyntax:
        namesLock.unlock();
        throw Poco::SyntaxException("setInternalName",
                "The name should only contain alphanumeric characters "
                "or \"-\", \"_\", \".\"");
    }
}

void Module::setCustomName(std::string customName)
{
    if (customName.empty() || customName.compare(internalName())==0)
    {
        mName = internalName();

        // update conf file prefix key
        setPrefixKey("module." + mName);

        return;
    }

    namesLock.writeLock();

    switch (checkName(customName))
    {
    case nameOk:
        mName = customName;
        names.push_back(mName);
        namesLock.unlock();
        return;
    case nameExists:
        freeInternalName();
        namesLock.unlock();
        throw Poco::ExistsException("setCustomName",
                customName + " already in use");
    case nameBadSyntax:
        freeInternalName();
        namesLock.unlock();
        throw Poco::SyntaxException("setCustomName",
                "The name should only contain alphanumeric characters "
                "or \"-\", \"_\", \".\"");
    }
}

ModuleFactory* Module::parent()
{
    if (mParent)
        return mParent;
    else
        throw Poco::InvalidAccessException("parent",
                "This module has no valid parent factory");
}

#include "Poco/RegularExpression.h"

Module::NameStatus Module::checkName(std::string newName)
{
    // check syntax
    Poco::RegularExpression regex("^[0-9a-zA-Z\\._-]+$");
    if (!regex.match(newName))
        return nameBadSyntax;

    // check existance
    for (std::vector<std::string>::iterator it = names.begin(),
            ite = names.end(); it != ite; it++)
        if (it->compare(newName)==0)
            return nameExists;

    return nameOk;
}

void Module::freeInternalName()
{
    // verify that this is a module creation process
    if (!name().empty())
        return;

    for (std::vector<std::string>::reverse_iterator it = names.rbegin(),
            ite = names.rend(); it != ite; it++ )
    {
        if (it->compare(internalName())==0)
        {
            names.erase((it+1).base());
            return;
        }
    }
}

void Module::run()
{
	expireOutData();

	setRunningState(ModuleTask::retrievingInDataLocks);
	int startCond = startCondition();

	mergeTasks(portsWithNewData());

	setRunningState(ModuleTask::processing);
	process(startCond);
}

bool Module::sleep(long milliseconds)
{
	if (*runningTask)
		return (*runningTask)->sleep(milliseconds);

	Poco::Thread::sleep(milliseconds);
	return false;
}

bool Module::yield()
{
	if (*runningTask)
		return (*runningTask)->yield();

	Poco::Thread::yield();
	return false;
}

void Module::setProgress(float progress)
{
	if (*runningTask == NULL)
		return;

	(*runningTask)->setProgress(progress);
}

bool Module::isCancelled()
{
	if (*runningTask == NULL)
		return false;

	return (*runningTask)->isCancelled();
}

void Module::cancel()
{
	if (*runningTask)
		(*runningTask)->cancel();

	throw Poco::RuntimeException(name(), "cancel. not in a task");
}

InPort* Module::triggingPort()
{
	if (*runningTask)
		return (*runningTask)->triggingPort();

	throw Poco::RuntimeException(name(), "querying trigging port. not in a task");
}

void Module::setRunningState(ModuleTask::RunningStates state)
{
	if (*runningTask == NULL)
		return;

	(*runningTask)->setRunningState(state);
}

ModuleTask::RunningStates Module::getRunningState()
{
	if (*runningTask == NULL)
		return ModuleTask::processing;

	return (*runningTask)->getRunningState();
}

bool Module::enqueueTask(ModuleTask* task)
{
	Poco::FastMutex::ScopedLock lock(taskMngtMutex);

	Poco::Util::Application::instance()
				             .getSubsystem<ThreadManager>()
				             .registerNewModuleTask(task);

	allTasks.insert(task);
	taskQueue.push_back(task);

	if (taskQueue.size()>1)
		return false;

	// check in allTasks if there is a task that is running
	for (std::set<ModuleTask*>::iterator it = allTasks.begin(),
			ite = allTasks.end(); it != ite; it++)
	{
		switch ((*it)->getState())
		{
		case MergeableTask::TASK_STARTING:
		case MergeableTask::TASK_RUNNING:
			poco_information(logger(), task->name()
					+ ": a task is already running for " + name());
			return false;
		case MergeableTask::TASK_FALSE_START:
		case MergeableTask::TASK_IDLE: // probably self
		case MergeableTask::TASK_CANCELLING:
		case MergeableTask::TASK_FINISHED:
			break;
		default:
			poco_bugcheck_msg("unknown task state");
		}
	}

	return true;
}

void Module::popTask()
{
	Poco::ScopedLockWithUnlock<Poco::FastMutex> lock(taskMngtMutex);

	if (taskQueue.empty())
		return;

	ModuleTask* nextTask = taskQueue.front();
	poco_information(logger(), "poping out the next task: " + nextTask->name());
	taskQueue.pop_front();

	lock.unlock();

	Poco::Util::Application::instance()
			             .getSubsystem<ThreadManager>()
			             .startModuleTask(nextTask);
}

void Module::popTaskSync()
{
	Poco::ScopedLockWithUnlock<Poco::FastMutex> lock(taskMngtMutex);

	if (taskQueue.empty())
	{
		poco_information(logger(), (*runningTask)->name() + ": empty task queue, nothing to sync pop");
		return;
	}

	ModuleTask* nextTask = taskQueue.front();
	poco_information(logger(), "SYNC poping out the next task: " + nextTask->name());
	taskQueue.pop_front();

	lock.unlock();

	Poco::Util::Application::instance()
			             .getSubsystem<ThreadManager>()
			             .startSyncModuleTask(nextTask);
}

void Module::unregisterTask(ModuleTask* task)
{
	Poco::FastMutex::ScopedLock lock(taskMngtMutex);

	allTasks.erase(task);
}

void Module::mergeTasks(std::set<size_t> inPortIndexes)
{
	Poco::FastMutex::ScopedLock lock(taskMngtMutex);

	for (std::set<size_t>::iterator it = inPortIndexes.begin(),
			ite = inPortIndexes.end(); it != ite; )
	{
		InPort* trigPort = getInPort(*it);

		if (triggingPort() == trigPort)
		{
			it++;
			continue; // current task
		}

		bool found = false;

		// seek
		for (std::list<ModuleTask*>::iterator qIt = taskQueue.begin(),
				qIte = taskQueue.end(); qIt != qIte; qIt++)
		{
			poco_information(logger(), "taskQueue includes: " + (*qIt)->name());
			if ((*qIt)->triggingPort() == trigPort)
			{
				found = true;
				(*runningTask)->merge(*qIt);
				taskQueue.erase(qIt);
				poco_information(logger(), "slave task found, merging OK");
				break;
			}
		}

		if (!found)
		{
			poco_warning(logger(),
					"Unable to merge the task for " + trigPort->name()
					+ ". Retry.");
			if (yield())
				throw Poco::RuntimeException(name(), "Cancelation upon user request");
		}
		else
			it++;
	}
}
<commit_msg>Fix deadlock issue with task merging.<commit_after>/**
 * @file	src/Module.cpp
 * @date	dec. 2015
 * @author	PhRG - opticalp.fr
 */

/*
 Copyright (c) 2015 Ph. Renaud-Goud / Opticalp

 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
 in the Software without restriction, including without limitation the rights
 to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:

 The above copyright notice and this permission notice shall be included in
 all copies or substantial portions of the Software.

 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 THE SOFTWARE.
 */

#include "Module.h"
#include "ModuleFactory.h"
#include "ModuleManager.h"
#include "ThreadManager.h"
#include "ModuleTask.h"

#include "OutPort.h"

#include "Poco/NumberFormatter.h"
#include "Poco/NumberParser.h"

std::vector<std::string> Module::names;
Poco::RWLock Module::namesLock;

void Module::notifyCreation()
{
    // if not EmptyModule, add this to module manager
    if (mParent)
        Poco::Util::Application::instance().getSubsystem<ModuleManager>().addModule(this);
}

Module::~Module()
{
	// TODO: tasks?

    // notify parent factory
    if (mParent)
    {
        mParent->removeChildModule(this);

        // notify module manager
        Poco::Util::Application::instance().getSubsystem<ModuleManager>().removeModule(this);
    }
}

#include "Poco/Exception.h"

void Module::setInternalName(std::string internalName)
{
    namesLock.writeLock();

    switch (checkName(internalName))
    {
    case nameOk:
        mInternalName = internalName;
        names.push_back(mInternalName);
        namesLock.unlock();
        return;
    case nameExists:
        namesLock.unlock();
        throw Poco::ExistsException("setInternalName",
                internalName + " already in use");
    case nameBadSyntax:
        namesLock.unlock();
        throw Poco::SyntaxException("setInternalName",
                "The name should only contain alphanumeric characters "
                "or \"-\", \"_\", \".\"");
    }
}

void Module::setCustomName(std::string customName)
{
    if (customName.empty() || customName.compare(internalName())==0)
    {
        mName = internalName();

        // update conf file prefix key
        setPrefixKey("module." + mName);

        return;
    }

    namesLock.writeLock();

    switch (checkName(customName))
    {
    case nameOk:
        mName = customName;
        names.push_back(mName);
        namesLock.unlock();
        return;
    case nameExists:
        freeInternalName();
        namesLock.unlock();
        throw Poco::ExistsException("setCustomName",
                customName + " already in use");
    case nameBadSyntax:
        freeInternalName();
        namesLock.unlock();
        throw Poco::SyntaxException("setCustomName",
                "The name should only contain alphanumeric characters "
                "or \"-\", \"_\", \".\"");
    }
}

ModuleFactory* Module::parent()
{
    if (mParent)
        return mParent;
    else
        throw Poco::InvalidAccessException("parent",
                "This module has no valid parent factory");
}

#include "Poco/RegularExpression.h"

Module::NameStatus Module::checkName(std::string newName)
{
    // check syntax
    Poco::RegularExpression regex("^[0-9a-zA-Z\\._-]+$");
    if (!regex.match(newName))
        return nameBadSyntax;

    // check existance
    for (std::vector<std::string>::iterator it = names.begin(),
            ite = names.end(); it != ite; it++)
        if (it->compare(newName)==0)
            return nameExists;

    return nameOk;
}

void Module::freeInternalName()
{
    // verify that this is a module creation process
    if (!name().empty())
        return;

    for (std::vector<std::string>::reverse_iterator it = names.rbegin(),
            ite = names.rend(); it != ite; it++ )
    {
        if (it->compare(internalName())==0)
        {
            names.erase((it+1).base());
            return;
        }
    }
}

void Module::run()
{
	expireOutData();

	setRunningState(ModuleTask::retrievingInDataLocks);
	int startCond = startCondition();

	mergeTasks(portsWithNewData());

	setRunningState(ModuleTask::processing);
	process(startCond);
}

bool Module::sleep(long milliseconds)
{
	if (*runningTask)
		return (*runningTask)->sleep(milliseconds);

	Poco::Thread::sleep(milliseconds);
	return false;
}

bool Module::yield()
{
	if (*runningTask)
		return (*runningTask)->yield();

	Poco::Thread::yield();
	return false;
}

void Module::setProgress(float progress)
{
	if (*runningTask == NULL)
		return;

	(*runningTask)->setProgress(progress);
}

bool Module::isCancelled()
{
	if (*runningTask == NULL)
		return false;

	return (*runningTask)->isCancelled();
}

void Module::cancel()
{
	if (*runningTask)
		(*runningTask)->cancel();

	throw Poco::RuntimeException(name(), "cancel. not in a task");
}

InPort* Module::triggingPort()
{
	if (*runningTask)
		return (*runningTask)->triggingPort();

	throw Poco::RuntimeException(name(), "querying trigging port. not in a task");
}

void Module::setRunningState(ModuleTask::RunningStates state)
{
	if (*runningTask == NULL)
		return;

	(*runningTask)->setRunningState(state);
}

ModuleTask::RunningStates Module::getRunningState()
{
	if (*runningTask == NULL)
		return ModuleTask::processing;

	return (*runningTask)->getRunningState();
}

bool Module::enqueueTask(ModuleTask* task)
{
	Poco::FastMutex::ScopedLock lock(taskMngtMutex);

	Poco::Util::Application::instance()
				             .getSubsystem<ThreadManager>()
				             .registerNewModuleTask(task);

	allTasks.insert(task);
	taskQueue.push_back(task);

	if (taskQueue.size()>1)
		return false;

	// check in allTasks if there is a task that is running
	for (std::set<ModuleTask*>::iterator it = allTasks.begin(),
			ite = allTasks.end(); it != ite; it++)
	{
		switch ((*it)->getState())
		{
		case MergeableTask::TASK_STARTING:
		case MergeableTask::TASK_RUNNING:
			poco_information(logger(), task->name()
					+ ": a task is already running for " + name());
			return false;
		case MergeableTask::TASK_FALSE_START:
		case MergeableTask::TASK_IDLE: // probably self
		case MergeableTask::TASK_CANCELLING:
		case MergeableTask::TASK_FINISHED:
			break;
		default:
			poco_bugcheck_msg("unknown task state");
		}
	}

	return true;
}

void Module::popTask()
{
	Poco::ScopedLockWithUnlock<Poco::FastMutex> lock(taskMngtMutex);

	if (taskQueue.empty())
		return;

	ModuleTask* nextTask = taskQueue.front();
	poco_information(logger(), "poping out the next task: " + nextTask->name());
	taskQueue.pop_front();

	Poco::Util::Application::instance()
			             .getSubsystem<ThreadManager>()
			             .startModuleTask(nextTask);

	lock.unlock();
}

void Module::popTaskSync()
{
	Poco::ScopedLockWithUnlock<Poco::FastMutex> lock(taskMngtMutex);

	if (taskQueue.empty())
	{
		poco_information(logger(), (*runningTask)->name() + ": empty task queue, nothing to sync pop");
		return;
	}

	ModuleTask* nextTask = taskQueue.front();
	poco_information(logger(), "SYNC poping out the next task: " + nextTask->name());
	taskQueue.pop_front();

	lock.unlock();

	Poco::Util::Application::instance()
			             .getSubsystem<ThreadManager>()
			             .startSyncModuleTask(nextTask);
}

void Module::unregisterTask(ModuleTask* task)
{
	Poco::FastMutex::ScopedLock lock(taskMngtMutex);

	allTasks.erase(task);
}

void Module::mergeTasks(std::set<size_t> inPortIndexes)
{
	// Poco::FastMutex::ScopedLock lock(taskMngtMutex);
	taskMngtMutex.lock();

	for (std::set<size_t>::iterator it = inPortIndexes.begin(),
			ite = inPortIndexes.end(); it != ite; )
	{
		bool found = false;
		InPort* trigPort;

		try
		{
			trigPort = getInPort(*it);

			if (triggingPort() == trigPort)
			{
				it++;
				continue; // current task
			}

			// seek
			for (std::list<ModuleTask*>::iterator qIt = taskQueue.begin(),
					qIte = taskQueue.end(); qIt != qIte; qIt++)
			{
				poco_information(logger(), "taskQueue includes: " + (*qIt)->name());
				if ((*qIt)->triggingPort() == trigPort)
				{
					found = true;
					(*runningTask)->merge(*qIt);
					taskQueue.erase(qIt);
					poco_information(logger(), "slave task found, merging OK");
					break;
				}
			}
		}
		catch (...)
		{
			taskMngtMutex.unlock();
			throw;
		}

		if (!found)
		{
			taskMngtMutex.unlock();
			poco_warning(logger(),
					"Unable to merge the task for " + trigPort->name()
					+ ". Retry.");
			if (sleep(500))
				throw Poco::RuntimeException(name(), "Cancelation upon user request");
			taskMngtMutex.lock();
		}
		else
			it++;
	}

	taskMngtMutex.unlock();
}
<|endoftext|>