[haiku-commits] BRANCH axeld-github.launch_daemon [50782a79799a] docs/user/app data/system/boot src/servers/launch

  • From: axeld-github.launch_daemon <community@xxxxxxxxxxxx>
  • To: haiku-commits@xxxxxxxxxxxxx
  • Date: Fri, 17 Jul 2015 23:16:52 +0200 (CEST)

added 4 changesets to branch 'refs/remotes/axeld-github/launch_daemon'
old head: 76a6491de5596b9b0ca228b2bd33f8c6886abd2b
new head: 50782a79799a736a27ecc855ba333000fa810107
overview: https://github.com/axeld/haiku/compare/76a6491de559...50782a79799a

----------------------------------------------------------------------------

54b79f7a138e: BLaunchRoster: removed be_launch_roster again.

* Not implemented, an unused -- no need for a global instance.

413efdc010fe: Added BLaunchRoster documentation.

* Untested, and could use some more love when it comes to possible
error codes.

54cf826671cf: Added post-install script, and start UserBootscript again.

* This is the final missing piece of the former boot process.
* Removed the unused Bootscript, and Bootscript.cd files.

50782a79799a: launch_daemon: Jobs were started before their target.

* A job must not be launched when its target hasn't been launched
yet. This fixes Tracker launching when the mount_server scanned
the initial disk, even though the FirstBootPrompt was showing.
* Jobs are no longer initialized when their target has not been launched
yet. This also means that you cannot talk to a service beforehand in
this case.
* Slight refactoring and clarifying, even added some documentation :-)
* _TriggerJob() is now called _LaunchJob(), and does all the checks for
jobs that _LaunchJobs() does now for targets.

[ Axel Dörfler <axeld@xxxxxxxxxxxxxxxx> ]

----------------------------------------------------------------------------

18 files changed, 388 insertions(+), 331 deletions(-)
build/jam/packages/HaikuBootstrap | 2 +-
data/launch/system | 5 +
data/launch/user | 4 +
data/system/boot/Bootscript | 212 --------------------------
data/system/boot/Bootscript.cd | 70 ---------
data/system/boot/PostInstallScript | 22 +++
docs/user/app/LaunchRoster.dox | 255 ++++++++++++++++++++++++++++++++
docs/user/app/_app_intro.dox | 5 +-
headers/private/app/LaunchRoster.h | 3 -
src/kits/app/LaunchRoster.cpp | 3 -
src/servers/launch/BaseJob.cpp | 7 +-
src/servers/launch/BaseJob.h | 2 +-
src/servers/launch/Events.cpp | 9 +-
src/servers/launch/Job.cpp | 14 ++
src/servers/launch/Job.h | 2 +
src/servers/launch/LaunchDaemon.cpp | 89 ++++++-----
src/servers/launch/Target.cpp | 10 +-
src/servers/launch/Target.h | 5 +

############################################################################

Commit: 54b79f7a138ec7890e22ee3b92cc8d3dfefc0216
Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>
Date: Fri Jul 17 19:14:20 2015 UTC

BLaunchRoster: removed be_launch_roster again.

* Not implemented, an unused -- no need for a global instance.

----------------------------------------------------------------------------

diff --git a/headers/private/app/LaunchRoster.h
b/headers/private/app/LaunchRoster.h
index 6a4f961..827d667 100644
--- a/headers/private/app/LaunchRoster.h
+++ b/headers/private/app/LaunchRoster.h
@@ -51,8 +51,5 @@ private:
uint32 _reserved[5];
};

-// global BLaunchRoster instance
-extern const BLaunchRoster* be_launch_roster;
-

#endif // _LAUNCH_ROSTER_H
diff --git a/src/kits/app/LaunchRoster.cpp b/src/kits/app/LaunchRoster.cpp
index da1f732..7770534 100644
--- a/src/kits/app/LaunchRoster.cpp
+++ b/src/kits/app/LaunchRoster.cpp
@@ -21,9 +21,6 @@
using namespace BPrivate;


-const BLaunchRoster* be_launch_roster;
-
-
BLaunchRoster::Private::Private(BLaunchRoster* roster)
:
fRoster(roster)

############################################################################

Commit: 413efdc010fee3df46e414916d5139769f7045dc
Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>
Date: Fri Jul 17 19:54:23 2015 UTC

Added BLaunchRoster documentation.

* Untested, and could use some more love when it comes to possible
error codes.

----------------------------------------------------------------------------

diff --git a/docs/user/app/LaunchRoster.dox b/docs/user/app/LaunchRoster.dox
new file mode 100644
index 0000000..0fe375e
--- /dev/null
+++ b/docs/user/app/LaunchRoster.dox
@@ -0,0 +1,255 @@
+/*
+ * Copyright 2015 Haiku, Inc. All rights reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ * Axel Dörfler, axeld@xxxxxxxxxxxxxxxx
+ *
+ * Corresponds to:
+ * headers/private/app/LaunchRoster.h
+ * src/kits/app/LaunchRoster.cpp
+ */
+
+
+/*!
+ \file LaunchRoster.h
+ \ingroup app
+ \ingroup libbe
+ \brief Provides BLaunchRoster class.
+*/
+
+
+/*!
+ \class BLaunchRoster
+ \ingroup app
+ \ingroup libbe
+ \brief The BLaunchRoster class lets you communicate with the
launch_daemon.
+
+ \since Haiku R1
+*/
+
+
+/*!
+ \fn BLaunchRoster::BLaunchRoster()
+ \brief Creates a new BLaunchRoster and sets up the connection to the
+ launch_daemon.
+
+ \since Haiku R1
+*/
+
+
+/*!
+ \fn BLaunchRoster::~BLaunchRoster()
+ \brief Does nothing.
+
+ \since Haiku R1
+*/
+
+
+/*!
+ \name Querying
+*/
+
+
+//! @{
+
+
+/*!
+ \fn status_t BLaunchRoster::GetData(BMessage& data)
+ \brief Returns the launch data for your own application.
+
+ If your application has any data stored by the launch_daemon, you can
+ retrieve this data with this method. Typically, this will contain the
+ communication channels the launch_daemon created for your application,
+ if any.
+
+ \return \c B_OK if the launch data has been received successfully.
+
+ \since Haiku R1
+*/
+
+
+/*!
+ \fn status_t BLaunchRoster::GetData(const char* signature, BMessage&
data)
+ \brief Returns the launch data for the specified application.
+
+ If the application has any data stored by the launch_daemon, you can
+ retrieve this data with this method. Typically, this will contain the
+ communication channels the launch_daemon created for this application,
+ if any.
+
+ \param signature The app \a signature.
+ \return \c B_OK if the launch data has been received successfully.
+
+ \since Haiku R1
+*/
+
+
+/*!
+ \fn status_t BLaunchRoster::GetPort(const char* name)
+ \brief Returns the named or default port for your application.
+
+ If the launch_daemon created a port for your application with the given
+ name, you can retrieve it with this method. Note that this is not the
+ actual port name, but the name the port has been registered with with
+ the launch_daemon.
+
+ \param name The name of the port, if \c NULL, the default port is
returned.
+ \return The port ID, if successful, or an error code.
+
+ \since Haiku R1
+*/
+
+
+/*!
+ \fn status_t BLaunchRoster::GetPort(const char* signature, const char*
name)
+ \brief Returns the named or default port for the specified application.
+
+ If the launch_daemon created a port for the application with the given
name,
+ you can retrieve it with this method. Note that this is not the actual
port
+ name, but the name the port has been registered with with the
launch_daemon.
+
+ \param signature The app \a signature.
+ \param name The name of the port, if \c NULL, the default port is
returned.
+ \return The port ID, if successful, or an error code.
+
+ \since Haiku R1
+*/
+
+
+//! @}
+
+
+/*!
+ \name Controlling
+*/
+
+
+//! @{
+
+
+/*!
+ \fn status_t BLaunchRoster::Target(const char* name, const BMessage&
data,
+ const char* baseName)
+ \brief Launches the specified target (or a clone of it), and attaches
+ the specified data to it.
+
+ The \a baseName will, if non \c NULL, cause the target by this name to
+ be cloned, and named \a name. This allows you to create new targets with
+ different \a data.
+ For example. the app_server is using this to create different login
+ targets for different displays.
+
+ \param name The target name, as specified in the configuration files
+ \param data Additional data you can pass to the target. This argument
+ is currently ignored.
+ \param baseName The name of the target to be cloned. Use \c NULL if you
+ do not want to clone the target.
+ \return B_OK if the target could be launched, otherwise an error code.
+
+ \since Haiku R1
+*/
+
+
+/*!
+ \fn status_t BLaunchRoster::Target(const char* name, const BMessage*
data,
+ const char* baseName)
+ \brief Launches the specified target (or a clone of it), and attaches
+ the specified data to it.
+
+ \see status_t BLaunchRoster::Target(const char* name, const BMessage&
data,
+ const char* baseName)
+
+ \since Haiku R1
+*/
+
+
+/*!
+ \fn status_t BLaunchRoster::StartSession(const char* login)
+ \brief Starts a new launch session for the specified login.
+
+ This causes the launch_daemon to start itself under the specified
+ user, and to evaluate and process the user's launch configuration.
+
+ \param login The name of the user.
+ \return B_OK if the session could be created, otherwise an error code.
+
+ \since Haiku R1
+*/
+
+
+//! @}
+
+
+/*!
+ \name Events
+*/
+
+
+//! @{
+
+
+/*!
+ \fn status_t BLaunchRoster::RegisterEvent(const BMessenger& source,
+ const char* name)
+ \brief Registers an event with the launch_daemon.
+
+ Registering an event allows other applications to be triggered by this
+ event. If you register an event named "event", applications can listen
+ to it like this:
+\code
+on {
+ event
+}
+\endcode
+ Or
+\code
+on {
+ last-part-of-signature/event
+}
+\endcode
+
+ The latter form can be used to solve ambiguous event definitions.
+
+ \param source The messenger the event is coming from.
+ \param name The name of the event.
+ \return B_OK if the event could be registered, otherwise an error code.
+
+ \since Haiku R1
+*/
+
+
+/*!
+ \fn status_t BLaunchRoster::UnregisterEvent(const BMessenger& source,
+ const char* name)
+ \brief Unregisters an event previously registered with the
launch_daemon.
+
+ \param source The messenger the event is coming from.
+ \param name The name of the event.
+ \return B_OK if the event could be unregistered, otherwise an error
code.
+
+ \since Haiku R1
+*/
+
+
+/*!
+ \fn status_t BLaunchRoster::NotifyEvent(const BMessenger& source,
+ const char* name)
+ \brief Notifies the launch_daemon that an event has been triggered.
+
+ This causes the launch_daemon to notify all jobs, or targets listening
+ to this event, eventually leading them to be started.
+
+ You must have previously registered the event, in order to make the
+ launch_daemon do anything on a notification. Unknown event notifications
+ will be ignored.
+
+ \param source The messenger the event is coming from.
+ \param name The name of the event.
+ \return B_OK if the event could be notified, otherwise an error code.
+
+ \since Haiku R1
+*/
+
+
+//! @}
diff --git a/docs/user/app/_app_intro.dox b/docs/user/app/_app_intro.dox
index ec40ad1..556c283 100644
--- a/docs/user/app/_app_intro.dox
+++ b/docs/user/app/_app_intro.dox
@@ -1,5 +1,5 @@
/*
- * Copyright 2007 Haiku, Inc. All rights reserved.
+ * Copyright 2007-2015 Haiku, Inc. All rights reserved.
* Distributed under the terms of the MIT License.
*
* Authors:
@@ -14,7 +14,7 @@
native Haiku applications with a GUI. The application kit does
exactly as its name suggests; it is the basis for Haiku applications.
You
should read through this document and the documents referenced here
before
- moving on to any other part of the API.
+ moving on to any other part of the API.

The Application Kit classes can be divided into two groups: the
"messaging"
classes and the "system interaction" classes. The larger group contains
@@ -37,6 +37,7 @@
- BApplication
- BClipboard
- BCursor
+ - BLaunchRoster
- BPropertyInfo
- BRoster
*/

############################################################################

Commit: 54cf826671cf45b146d8d58e9e2b0ed25d4df147
Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>
Date: Fri Jul 17 20:15:38 2015 UTC

Added post-install script, and start UserBootscript again.

* This is the final missing piece of the former boot process.
* Removed the unused Bootscript, and Bootscript.cd files.

----------------------------------------------------------------------------

diff --git a/build/jam/packages/HaikuBootstrap
b/build/jam/packages/HaikuBootstrap
index 0d6f674..c015fe9 100644
--- a/build/jam/packages/HaikuBootstrap
+++ b/build/jam/packages/HaikuBootstrap
@@ -124,7 +124,7 @@ AddSymlinkToPackage bin : gzip : zcat ;
AddSymlinkToPackage bin : zdiff : zcmp ;

# scripts and data files
-local bootScripts = Bootscript Bootscript.cd SetupEnvironment
+local bootScripts = PostInstallScript SetupEnvironment
InstallerInitScript InstallerFinishScript ;
SEARCH on $(bootScripts) = [ FDirName $(HAIKU_TOP) data system boot ] ;
AddFilesToPackage boot : $(bootScripts) ;
diff --git a/data/launch/system b/data/launch/system
index 1b737fd..ba726cf 100644
--- a/data/launch/system
+++ b/data/launch/system
@@ -70,6 +70,11 @@ service x-vnd.Haiku-power_daemon {
legacy
}

+job post-install {
+ launch /bin/sh /system/boot/PostInstallScript
+ if file_exists /boot/system/settings/fresh_install
+}
+
target login {
job x-vnd.Haiku-autologin {
launch /system/bin/autologin
diff --git a/data/launch/user b/data/launch/user
index 7792beb..be034a9 100644
--- a/data/launch/user
+++ b/data/launch/user
@@ -17,6 +17,10 @@ target desktop {
}
}

+ job user-bootscript {
+ launch /bin/sh /boot/home/config/settings/boot/UserBootscript
+ }
+
job create-installer-link {
# When run from a read-only medium a.k.a. live desktop
if {
diff --git a/data/system/boot/Bootscript b/data/system/boot/Bootscript
deleted file mode 100644
index a6af7f0..0000000
--- a/data/system/boot/Bootscript
+++ /dev/null
@@ -1,212 +0,0 @@
-## The system's main boot script.
-
-##
-## Some functions used by the main script
-##
-
-# launch <executable path> [ <thread to wait for> [ <program args> ] ]
-
-launch() {
- toLaunch="$1"
- shift
- toWaitFor="$1"
- (( $# )) && shift
- if [ -f "/boot/$toLaunch" ]
- then
- "/boot/$toLaunch" $* &
- [ "$toWaitFor" != "" ] && waitfor "$toWaitFor"
- return 1
- else
- echo There is no "$toLaunch"
- fi
- return 0
-}
-
-# launchscript <script path>
-
-launchscript() {
- if [ -f "/boot/$1" ]
- then
- . "/boot/$1"
- fi
-}
-
-# runprog <executable path>
-
-runprog() {
- if [ -f "/boot/$1" ]
- then
- "/boot/$1"
- return 1
- else
- echo There is no "$1"
- fi
- return 0
-}
-
-##
-## Main script starts here
-##
-
-# Set up stdin/out/err to nirvana
-
-exec </dev/null
-exec >/dev/null 2>&1
-
-# Standard locations of boot files
-SCRIPTS=system/boot
-SERVERS=system/servers
-
-# clean the shared memory dir
-shmDir=/var/shared_memory
-rm -rf $shmDir
-mkdir -p $shmDir
-chmod 777 $shmDir
-
-# Set up the environment
-
-export SAFEMODE=`/bin/safemode`
-
-launchscript $SCRIPTS/SetupEnvironment
-
-# If the boot volume is a CD we use another script
-isReadOnly=`/bin/isvolume -readonly-partition /boot`
-if [ "$isReadOnly" = "yes" ]; then
- # block the CD tray (avoid accidental ejection)
- # This option stays 'on' even if we continue booting to the desktop.
- /bin/eject -b /boot
-else
- # Sets timezone etc.
- runprog system/bin/clockconfig
-fi
-
-# Create /tmp dir, and make sure it's empty
-
-TMPDIR=/boot/system/cache/tmp
-if [ ! -d $TMPDIR ]; then
- mkdir -f $TMPDIR
- chmod a+rwx $TMPDIR
-else
- rm -rf $TMPDIR/*
-fi
-
-
-# Launch servers
-
-# We must wait for the app_server and registrar to be ready
-launch $SERVERS/registrar _roster_thread_ # launch registrar
-
-# If app_server doesn't exist, just run consoled.
-if [ ! -f "/boot/$SERVERS/app_server" ]; then
- /bin/consoled
- exit
-fi
-
-launch $SERVERS/debug_server # launch debug_server
-
-launch $SERVERS/package_daemon
-
-# Init Network
-if [ "$SAFEMODE" != "yes" ]; then
- launch $SERVERS/net_server # launch
net_server
-fi
-
-launch $SERVERS/app_server picasso # launch app_server
-
-if [ "$SAFEMODE" != "yes" ]; then
- launch $SERVERS/syslog_daemon
- waitfor _input_server_event_loop_ # wait for input devices
-fi
-
-# Now ask the user if he wants to run the Installer or continue to the Desktop.
-localeSettings=/boot/home/config/settings/Locale\ settings
-if [ "$isReadOnly" = "yes" -o ! -e "$localeSettings" ]; then
- /bin/FirstBootPrompt
- if [ $? -eq 0 ]; then
- launchscript $SCRIPTS/Bootscript.cd
- exit 0 # and return
- elif [ "$isReadOnly" = "yes" ] ; then
- # Create Installer link (using the write overlay)
- ln -sf /boot/system/apps/Installer /boot/home/Desktop/Installer
- fi
-fi
-
-
-if [ -e /etc/users ]; then
- # TODO: system/Login needs to be fixed to launch the mount_server!
- launch system/Login
- # nothing more
-else
- cd /boot/home
-
- launch $SERVERS/mount_server
- waitfor -m application/x-vnd.Haiku-mount_server
- # delay the boot script until all previous volumes have been mounted
- hey -s mount_server DO InitialScan
-
- launch system/Tracker
- launch system/Deskbar
-fi
-
-if [ "$SAFEMODE" != "yes" ]; then
- launch $SERVERS/media_server
- launch $SERVERS/midi_server
-fi
-
-# Launch Print Server
-if [ "$SAFEMODE" != "yes" ]; then
- launch $SERVERS/print_server
-fi
-
-# Launch Mail Daemon (if enabled on startup)
-if [ "$SAFEMODE" != "yes" ]; then
- launch $SERVERS/mail_daemon "" -E
-fi
-
-# Launch CDDB Daemon
-if [ "$SAFEMODE" != "yes" ]; then
- launch $SERVERS/cddb_daemon ""
-fi
-
-# Launch Notification Server
-if [ "$SAFEMODE" != "yes" ]; then
- launch $SERVERS/notification_server ""
-fi
-
-# Launch Power Daemon
-if [ "$SAFEMODE" != "yes" ]; then
- launch $SERVERS/power_daemon ""
-fi
-
-# Check for daylight saving time
-launch system/bin/dstcheck
-
-# Synchronize network time
-launch system/preferences/Time "" --update
-
-if [ "$SAFEMODE" != "yes" ]; then
- # Start user boot script
- if [ -f $HOME/config/settings/boot/UserBootscript ]; then
- . $HOME/config/settings/boot/UserBootscript
- fi
-fi
-
-# Check for fresh install and run post install scripts.
-freshInstallIndicator=/boot/system/settings/fresh_install
-postInstallDir=boot/post-install
-if [ -e $freshInstallIndicator ]; then
- # wait a moment for things to calm down a bit
- sleep 3
-
- # execute scripts
- for f in /boot/system/$postInstallDir/*.sh
- do
- if [ -f $f ]; then
- echo "Running post install script $f ..." > /dev/dprintf
- $f
- fi
- done
-
- sync
- rm $freshInstallIndicator
-fi
diff --git a/data/system/boot/Bootscript.cd b/data/system/boot/Bootscript.cd
deleted file mode 100644
index 8eebd37..0000000
--- a/data/system/boot/Bootscript.cd
+++ /dev/null
@@ -1,70 +0,0 @@
-## The system's main CD boot script.
-
-##
-## Some functions used by the main script
-##
-
-# launch <executable path> [thread to wait for]
-
-launch() {
- if [ -f "/boot/$1" ]
- then
- "/boot/$1" &
- [ "$2" != "" ] && waitfor "$2"
- return 1
- else
- echo There is no "$1"
- fi
- return 0
-}
-
-# launchscript <script path>
-
-launchscript() {
- if [ -f "/boot/$1" ]
- then
- . "/boot/$1"
- fi
-}
-
-# runprog <executable path>
-
-runprog() {
- if [ -f "/boot/$1" ]
- then
- "/boot/$1"
- return 1
- else
- echo There is no "$1"
- fi
- return 0
-}
-
-##
-## Main script starts here
-##
-
-
-# Launch Installer
-
-cd /boot/home
-if [ -x /boot/system/apps/Installer ]; then
- /boot/system/apps/Installer
-else
- /boot/system/apps/Terminal
-fi
-
-# sync disks
-/bin/sync
-
-# prepare for reboot
-# (reboot quickly in 10 seconds)
-# (we must start the shutdown process before /boot is ejected)
-/bin/shutdown -r -q -d 10 &
-
-# unblock the CD tray
-/bin/eject -u /boot
-# and open it before rebooting
-/bin/eject /boot
-
-
diff --git a/data/system/boot/PostInstallScript
b/data/system/boot/PostInstallScript
new file mode 100644
index 0000000..9b22092
--- /dev/null
+++ b/data/system/boot/PostInstallScript
@@ -0,0 +1,22 @@
+#!/bin/sh
+
+# Check for fresh install and run post install scripts.
+
+freshInstallIndicator=/boot/system/settings/fresh_install
+postInstallDir=boot/post-install
+if [ -e $freshInstallIndicator ]; then
+ # wait a moment for things to calm down a bit
+ sleep 3
+
+ # execute scripts
+ for f in /boot/system/$postInstallDir/*.sh
+ do
+ if [ -f $f ]; then
+ echo "Running post install script $f ..." > /dev/dprintf
+ $f
+ fi
+ done
+
+ sync
+ rm $freshInstallIndicator
+fi

############################################################################

Commit: 50782a79799a736a27ecc855ba333000fa810107
Author: Axel Dörfler <axeld@xxxxxxxxxxxxxxxx>
Date: Fri Jul 17 20:59:17 2015 UTC

launch_daemon: Jobs were started before their target.

* A job must not be launched when its target hasn't been launched
yet. This fixes Tracker launching when the mount_server scanned
the initial disk, even though the FirstBootPrompt was showing.
* Jobs are no longer initialized when their target has not been launched
yet. This also means that you cannot talk to a service beforehand in
this case.
* Slight refactoring and clarifying, even added some documentation :-)
* _TriggerJob() is now called _LaunchJob(), and does all the checks for
jobs that _LaunchJobs() does now for targets.

----------------------------------------------------------------------------

diff --git a/src/servers/launch/BaseJob.cpp b/src/servers/launch/BaseJob.cpp
index fd11fdc..555375e 100644
--- a/src/servers/launch/BaseJob.cpp
+++ b/src/servers/launch/BaseJob.cpp
@@ -93,10 +93,15 @@ BaseJob::SetEvent(::Event* event)
}


+/*! Determines whether the events of this job has been triggered
+ already or not.
+ Note, if this job does not have any events, this method returns
+ \c true.
+*/
bool
BaseJob::EventHasTriggered() const
{
- return Event() != NULL && Event()->Triggered();
+ return Event() == NULL || Event()->Triggered();
}


diff --git a/src/servers/launch/BaseJob.h b/src/servers/launch/BaseJob.h
index 41d38f0..26df36a 100644
--- a/src/servers/launch/BaseJob.h
+++ b/src/servers/launch/BaseJob.h
@@ -28,7 +28,7 @@ public:
const ::Condition* Condition() const;
::Condition* Condition();
void
SetCondition(::Condition* condition);
- bool
CheckCondition(ConditionContext& context) const;
+ virtual bool
CheckCondition(ConditionContext& context) const;

const ::Event* Event() const;
::Event* Event();
diff --git a/src/servers/launch/Events.cpp b/src/servers/launch/Events.cpp
index 8b46df3..6642f66 100644
--- a/src/servers/launch/Events.cpp
+++ b/src/servers/launch/Events.cpp
@@ -539,10 +539,15 @@ Events::TriggerRegisteredEvent(Event* event, const char*
name)
}


+/*! This will trigger a demand event, if it exists.
+
+ \return \c true, if there is a demand event, and it has been
+ triggered by this call. \c false if not.
+*/
/*static*/ bool
Events::TriggerDemand(Event* event)
{
- if (event == NULL)
+ if (event == NULL || event->Triggered())
return false;

if (EventContainer* container = dynamic_cast<EventContainer*>(event)) {
@@ -551,7 +556,7 @@ Events::TriggerDemand(Event* event)
Event* childEvent = container->Events().ItemAt(index);
if (dynamic_cast<DemandEvent*>(childEvent) != NULL) {
childEvent->Trigger();
- return true;
+ break;
}
if (dynamic_cast<EventContainer*>(childEvent) != NULL) {
if (TriggerDemand(childEvent))
diff --git a/src/servers/launch/Job.cpp b/src/servers/launch/Job.cpp
index 1092ae9..224a17e 100644
--- a/src/servers/launch/Job.cpp
+++ b/src/servers/launch/Job.cpp
@@ -41,6 +41,10 @@ Job::Job(const Job& other)
fTarget(other.Target())
{
fCondition = other.fCondition;
+ // TODO: copy events
+ //fEvent = other.fEvent;
+ fEnvironment = other.fEnvironment;
+ fSourceFiles = other.fSourceFiles;

for (int32 i = 0; i < other.Arguments().CountStrings(); i++)
AddArgument(other.Arguments().StringAt(i));
@@ -172,6 +176,16 @@ Job::AddRequirement(const char* requirement)
}


+bool
+Job::CheckCondition(ConditionContext& context) const
+{
+ if (Target() != NULL && !Target()->HasLaunched())
+ return false;
+
+ return BaseJob::CheckCondition(context);
+}
+
+
status_t
Job::Init(const Finder& finder, std::set<BString>& dependencies)
{
diff --git a/src/servers/launch/Job.h b/src/servers/launch/Job.h
index 0adc504..e2ee0b4 100644
--- a/src/servers/launch/Job.h
+++ b/src/servers/launch/Job.h
@@ -54,6 +54,8 @@ public:
BStringList& Requirements();
void AddRequirement(const
char* requirement);

+ virtual bool
CheckCondition(ConditionContext& context) const;
+
status_t Init(const Finder& jobs,

std::set<BString>& dependencies);
status_t InitCheck() const;
diff --git a/src/servers/launch/LaunchDaemon.cpp
b/src/servers/launch/LaunchDaemon.cpp
index 095fe14..2d59a4c 100644
--- a/src/servers/launch/LaunchDaemon.cpp
+++ b/src/servers/launch/LaunchDaemon.cpp
@@ -134,10 +134,10 @@ private:
const
char* name);
void _AddJob(Target* target,
bool service,

BMessage& message);
- void _InitJobs();
- void _LaunchJobs(Target*
target);
- void _TriggerJob(Job* job);
- void _AddLaunchJob(Job* job);
+ void _InitJobs(Target*
target);
+ void _LaunchJobs(Target*
target,
+ bool
forceNow = false);
+ void _LaunchJob(Job* job,
bool forceNow = false);
void _AddTarget(Target*
target);
void _SetCondition(BaseJob*
job,
const
BMessage& message);
@@ -361,7 +361,7 @@ LaunchDaemon::ReadyToRun()
fUserMode ? B_FIND_PATHS_USER_ONLY : B_FIND_PATHS_SYSTEM_ONLY,
paths);
_ReadPaths(paths);

- _InitJobs();
+ _InitJobs(NULL);
_LaunchJobs(NULL);

// Launch run targets (ignores events)
@@ -414,13 +414,13 @@ LaunchDaemon::MessageReceived(BMessage* message)
break;

Job* job = FindJob(name);
- if (job != NULL && job->EventHasTriggered()) {
- _TriggerJob(job);
+ if (job != NULL) {
+ _LaunchJob(job);
break;
}

Target* target = FindTarget(name);
- if (target != NULL && target->EventHasTriggered()) {
+ if (target != NULL) {
_LaunchJobs(target);
break;
}
@@ -442,7 +442,7 @@ LaunchDaemon::_HandleGetLaunchData(BMessage* message)
return;

BMessage reply((uint32)B_OK);
- bool triggerJob = true;
+ bool launchJob = true;

Job* job = FindJob(get_leaf(message->GetString("name")));
if (job == NULL) {
@@ -454,7 +454,7 @@ LaunchDaemon::_HandleGetLaunchData(BMessage* message)
}
reply.what = B_NAME_NOT_FOUND;
} else if (!job->IsLaunched()) {
- if (!job->CheckCondition(*this)) {
+ if (job->InitCheck() == B_NO_INIT ||
!job->CheckCondition(*this)) {
// The job exists, but cannot be started yet, as its
// conditions are not met; don't make it available yet
// TODO: we may not want to initialize jobs with
conditions
@@ -465,9 +465,8 @@ LaunchDaemon::_HandleGetLaunchData(BMessage* message)
// The job is not triggered by demand; we
cannot start it now
reply.what = B_NO_INIT;
} else {
- // The job has already been triggered, don't
trigger it
- // again
- triggerJob = false;
+ // The job has already been triggered, don't
launch it again
+ launchJob = false;
}
}
}
@@ -490,8 +489,9 @@ LaunchDaemon::_HandleGetLaunchData(BMessage* message)
iterator->second.GetInt32("port", -1));
}

- if (triggerJob)
- _TriggerJob(job);
+ // Launch the job if it hasn't been launched already
+ if (launchJob)
+ _LaunchJob(job);
}
message->SendReply(&reply);
}
@@ -932,13 +932,20 @@ LaunchDaemon::_AddJob(Target* target, bool service,
BMessage& message)
}


+/*! Initializes all jobs for the specified target (may be \c NULL).
+ Jobs that cannot be initialized, and those that never will be due to
+ conditions, will be removed from the list.
+*/
void
-LaunchDaemon::_InitJobs()
+LaunchDaemon::_InitJobs(Target* target)
{
for (JobMap::iterator iterator = fJobs.begin(); iterator !=
fJobs.end();) {
Job* job = iterator->second;
JobMap::iterator remove = iterator++;

+ if (job->Target() != target)
+ continue;
+
status_t status = B_NO_INIT;
if (job->IsEnabled()) {
// Filter out jobs that have a constant and failing
condition
@@ -965,52 +972,64 @@ LaunchDaemon::_InitJobs()


/*! Adds all jobs for the specified target (may be \c NULL) to the launch
- queue, except those that are triggered by events.
+ queue, except those that are triggered by events that haven't been
+ triggered yet.
+
+ Unless \a forceNow is true, the target is only launched if its events,
+ if any, have been triggered already, and its conditions are met.
*/
void
-LaunchDaemon::_LaunchJobs(Target* target)
+LaunchDaemon::_LaunchJobs(Target* target, bool forceNow)
{
- if (target != NULL && !target->CheckCondition(*this))
+ if (!forceNow && target != NULL && (!target->EventHasTriggered()
+ || !target->CheckCondition(*this))) {
return;
+ }
+
+ if (target != NULL && !target->HasLaunched()) {
+ target->SetLaunched(true);
+ _InitJobs(target);
+ }

for (JobMap::iterator iterator = fJobs.begin(); iterator != fJobs.end();
iterator++) {
Job* job = iterator->second;
- if (job->Target() == target
- && (job->Event() == NULL || job->Event()->Triggered()))
- _TriggerJob(job);
+ if (job->Target() == target)
+ _LaunchJob(job);
}
}


+/*! Adds the specified \a job to the launch queue
+ queue, except those that are triggered by events.
+
+ Unless \a forceNow is true, the target is only launched if its events,
+ if any, have been triggered already.
+
+ Calling this method will trigger a demand event.
+*/
void
-LaunchDaemon::_TriggerJob(Job* job)
+LaunchDaemon::_LaunchJob(Job* job, bool forceNow)
{
- if (job == NULL)
+ if (job == NULL || job->IsLaunched() || !forceNow
+ && (!job->EventHasTriggered() || !job->CheckCondition(*this)
+ || Events::TriggerDemand(job->Event()))) {
return;
+ }

int32 count = job->Requirements().CountStrings();
for (int32 index = 0; index < count; index++) {
Job* requirement = FindJob(job->Requirements().StringAt(index));
if (requirement != NULL)
- _TriggerJob(requirement);
+ _LaunchJob(requirement);
}

- if (job->EventHasTriggered() || !Events::TriggerDemand(job->Event()))
- _AddLaunchJob(job);
-}
-
-
-void
-LaunchDaemon::_AddLaunchJob(Job* job)
-{
if (job->Target() != NULL)
job->Target()->ResolveSourceFiles();
if (job->Event() != NULL)
job->Event()->ResetTrigger();

- if (!job->IsLaunched() && job->CheckCondition(*this))
- fJobQueue.AddJob(job);
+ fJobQueue.AddJob(job);
}


diff --git a/src/servers/launch/Target.cpp b/src/servers/launch/Target.cpp
index 34bd133..91e09e7 100644
--- a/src/servers/launch/Target.cpp
+++ b/src/servers/launch/Target.cpp
@@ -9,7 +9,8 @@

Target::Target(const char* name)
:
- BaseJob(name)
+ BaseJob(name),
+ fLaunched(false)
{
}

@@ -21,6 +22,13 @@ Target::AddData(const char* name, BMessage& data)
}


+void
+Target::SetLaunched(bool launched)
+{
+ fLaunched = launched;
+}
+
+
status_t
Target::Execute()
{
diff --git a/src/servers/launch/Target.h b/src/servers/launch/Target.h
index 0b4b37d..0d0ece0 100644
--- a/src/servers/launch/Target.h
+++ b/src/servers/launch/Target.h
@@ -22,11 +22,16 @@ public:
const BMessage& Data() const
{
return fData; }

+ bool HasLaunched() const
+ {
return fLaunched; }
+ void SetLaunched(bool
launched);
+
protected:
virtual status_t Execute();

private:
BMessage fData;
+ bool fLaunched;
};




Other related posts: