2 * Copyright 2015-2016, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
16 #include <MessagePrivate.h>
17 #include <RosterPrivate.h>
18 #include <user_group.h>
24 Job::Job(const char* name
)
29 fCreateDefaultPort(false),
31 fInitStatus(B_NO_INIT
),
34 fToken((uint32
)B_PREFERRED_TOKEN
),
35 fLaunchStatus(B_NO_INIT
),
37 fPendingLaunchDataReplies(0, false)
39 mutex_init(&fLaunchStatusLock
, "launch status lock");
43 Job::Job(const Job
& other
)
45 BaseJob(other
.Name()),
46 fEnabled(other
.IsEnabled()),
47 fService(other
.IsService()),
48 fCreateDefaultPort(other
.CreateDefaultPort()),
49 fLaunching(other
.IsLaunching()),
50 fInitStatus(B_NO_INIT
),
53 fToken((uint32
)B_PREFERRED_TOKEN
),
54 fLaunchStatus(B_NO_INIT
),
55 fTarget(other
.Target()),
56 fPendingLaunchDataReplies(0, false)
58 mutex_init(&fLaunchStatusLock
, "launch status lock");
60 fCondition
= other
.fCondition
;
62 //fEvent = other.fEvent;
63 fEnvironment
= other
.fEnvironment
;
64 fSourceFiles
= other
.fSourceFiles
;
66 for (int32 i
= 0; i
< other
.Arguments().CountStrings(); i
++)
67 AddArgument(other
.Arguments().StringAt(i
));
69 for (int32 i
= 0; i
< other
.Requirements().CountStrings(); i
++)
70 AddRequirement(other
.Requirements().StringAt(i
));
72 PortMap::const_iterator constIterator
= other
.Ports().begin();
73 for (; constIterator
!= other
.Ports().end(); constIterator
++) {
75 std::make_pair(constIterator
->first
, constIterator
->second
));
78 PortMap::iterator iterator
= fPortMap
.begin();
79 for (; iterator
!= fPortMap
.end(); iterator
++)
80 iterator
->second
.RemoveData("port");
91 Job::TeamRegistrator() const
93 return fTeamRegistrator
;
98 Job::SetTeamRegistrator(::TeamRegistrator
* registrator
)
100 fTeamRegistrator
= registrator
;
105 Job::IsEnabled() const
112 Job::SetEnabled(bool enable
)
119 Job::IsService() const
126 Job::SetService(bool service
)
133 Job::CreateDefaultPort() const
135 return fCreateDefaultPort
;
140 Job::SetCreateDefaultPort(bool createPort
)
142 fCreateDefaultPort
= createPort
;
147 Job::AddPort(BMessage
& data
)
149 const char* name
= data
.GetString("name");
150 fPortMap
.insert(std::pair
<BString
, BMessage
>(BString(name
), data
));
155 Job::Arguments() const
169 Job::AddArgument(const char* argument
)
171 fArguments
.Add(argument
);
183 Job::SetTarget(::Target
* target
)
190 Job::Requirements() const
192 return fRequirements
;
199 return fRequirements
;
204 Job::AddRequirement(const char* requirement
)
206 fRequirements
.Add(requirement
);
225 Job::AddPending(const char* pending
)
227 fPendingJobs
.Add(pending
);
232 Job::CheckCondition(ConditionContext
& context
) const
234 if (Target() != NULL
&& !Target()->HasLaunched())
237 return BaseJob::CheckCondition(context
);
242 Job::Init(const Finder
& finder
, std::set
<BString
>& dependencies
)
244 // Only initialize the jobs once
245 if (fInitStatus
!= B_NO_INIT
)
251 fTarget
->AddDependency(this);
253 // Check dependencies
255 for (int32 index
= 0; index
< Requirements().CountStrings(); index
++) {
256 const BString
& requires
= Requirements().StringAt(index
);
257 if (dependencies
.find(requires
) != dependencies
.end()) {
258 // Found a cyclic dependency
260 return fInitStatus
= B_ERROR
;
262 dependencies
.insert(requires
);
264 Job
* dependency
= finder
.FindJob(requires
);
265 if (dependency
!= NULL
) {
266 std::set
<BString
> subDependencies
= dependencies
;
268 fInitStatus
= dependency
->Init(finder
, subDependencies
);
269 if (fInitStatus
!= B_OK
) {
274 fInitStatus
= _AddRequirement(dependency
);
276 ::Target
* target
= finder
.FindTarget(requires
);
278 fInitStatus
= _AddRequirement(dependency
);
280 // Could not find dependency
281 fInitStatus
= B_NAME_NOT_FOUND
;
284 if (fInitStatus
!= B_OK
) {
295 Job::InitCheck() const
316 Job::Port(const char* name
) const
318 PortMap::const_iterator found
= fPortMap
.find(name
);
319 if (found
!= fPortMap
.end())
320 return found
->second
.GetInt32("port", -1);
322 return B_NAME_NOT_FOUND
;
327 Job::DefaultPort() const
334 Job::SetDefaultPort(port_id port
)
338 PortMap::iterator iterator
= fPortMap
.begin();
339 for (; iterator
!= fPortMap
.end(); iterator
++) {
341 if (iterator
->second
.HasString("name"))
344 iterator
->second
.SetInt32("port", (int32
)port
);
355 std::vector
<const char*> environment
;
356 for (const char** variable
= (const char**)environ
; variable
[0] != NULL
;
358 environment
.push_back(variable
[0]);
361 if (Target() != NULL
)
362 _AddStringList(environment
, Target()->Environment());
363 _AddStringList(environment
, Environment());
365 // Resolve source files
366 BStringList sourceFilesEnvironment
;
367 GetSourceFilesEnvironment(sourceFilesEnvironment
);
368 _AddStringList(environment
, sourceFilesEnvironment
);
370 environment
.push_back(NULL
);
372 if (fArguments
.IsEmpty()) {
373 // Launch by signature
374 BString
signature("application/");
377 return _Launch(signature
.String(), NULL
, 0, NULL
, &environment
[0]);
380 // Build argument vector
383 status_t status
= get_ref_for_path(
384 Utility::TranslatePath(fArguments
.StringAt(0).String()), &ref
);
385 if (status
!= B_OK
) {
386 _SetLaunchStatus(status
);
390 std::vector
<BString
> strings
;
391 std::vector
<const char*> args
;
393 size_t count
= fArguments
.CountStrings() - 1;
395 for (int32 i
= 1; i
< fArguments
.CountStrings(); i
++) {
396 strings
.push_back(Utility::TranslatePath(fArguments
.StringAt(i
)));
397 args
.push_back(strings
.back());
399 args
.push_back(NULL
);
402 // Launch via entry_ref
403 return _Launch(NULL
, &ref
, count
, &args
[0], &environment
[0]);
408 Job::IsLaunched() const
410 return fLaunchStatus
!= B_NO_INIT
;
415 Job::IsRunning() const
428 SetState(B_JOB_STATE_WAITING_TO_RUN
);
430 MutexLocker
locker(fLaunchStatusLock
);
431 fLaunchStatus
= B_NO_INIT
;
436 Job::CanBeLaunched() const
438 // Services cannot be launched while they are running
439 return IsEnabled() && !IsLaunching() && (!IsService() || !IsRunning());
444 Job::IsLaunching() const
451 Job::SetLaunching(bool launching
)
453 fLaunching
= launching
;
458 Job::HandleGetLaunchData(BMessage
* message
)
460 MutexLocker
launchLocker(fLaunchStatusLock
);
462 return _SendLaunchDataReply(message
);
464 return fPendingLaunchDataReplies
.AddItem(message
) ? B_OK
: B_NO_MEMORY
;
469 Job::GetMessenger(BMessenger
& messenger
)
471 if (fDefaultPort
< 0)
472 return B_NAME_NOT_FOUND
;
474 BMessenger::Private(messenger
).SetTo(fTeam
, fDefaultPort
, fToken
);
482 status_t status
= BJob::Run();
484 // Jobs can be relaunched at any time
486 SetState(B_JOB_STATE_WAITING_TO_RUN
);
495 status_t status
= B_OK
;
496 if (!IsRunning() || !IsService())
499 debug_printf("Ignore launching %s\n", Name());
509 PortMap::const_iterator iterator
= Ports().begin();
510 for (; iterator
!= Ports().end(); iterator
++) {
511 port_id port
= iterator
->second
.GetInt32("port", -1);
519 Job::_AddRequirement(BJob
* dependency
)
521 if (dependency
== NULL
)
524 switch (dependency
->State()) {
525 case B_JOB_STATE_WAITING_TO_RUN
:
526 case B_JOB_STATE_STARTED
:
527 case B_JOB_STATE_IN_PROGRESS
:
528 AddDependency(dependency
);
531 case B_JOB_STATE_SUCCEEDED
:
532 // Just queue it without any dependencies
535 case B_JOB_STATE_FAILED
:
536 case B_JOB_STATE_ABORTED
:
537 // TODO: return appropriate error
546 Job::_AddStringList(std::vector
<const char*>& array
, const BStringList
& list
)
548 int32 count
= list
.CountStrings();
549 for (int32 index
= 0; index
< count
; index
++) {
550 array
.push_back(list
.StringAt(index
).String());
556 Job::_SetLaunchStatus(status_t launchStatus
)
558 MutexLocker
launchLocker(fLaunchStatusLock
);
559 fLaunchStatus
= launchStatus
!= B_NO_INIT
? launchStatus
: B_ERROR
;
560 launchLocker
.Unlock();
562 _SendPendingLaunchDataReplies();
567 Job::_SendLaunchDataReply(BMessage
* message
)
569 BMessage
reply(fTeam
< 0 ? fTeam
: (uint32
)B_OK
);
570 if (reply
.what
== B_OK
) {
571 reply
.AddInt32("team", fTeam
);
573 PortMap::const_iterator iterator
= fPortMap
.begin();
574 for (; iterator
!= fPortMap
.end(); iterator
++) {
576 if (iterator
->second
.HasString("name"))
577 name
<< iterator
->second
.GetString("name") << "_";
580 reply
.AddInt32(name
.String(),
581 iterator
->second
.GetInt32("port", -1));
585 message
->SendReply(&reply
);
592 Job::_SendPendingLaunchDataReplies()
594 for (int32 i
= 0; i
< fPendingLaunchDataReplies
.CountItems(); i
++)
595 _SendLaunchDataReply(fPendingLaunchDataReplies
.ItemAt(i
));
597 fPendingLaunchDataReplies
.MakeEmpty();
601 /*! Creates the ports for a newly launched job. If the registrar already
602 pre-registered the application, \c fDefaultPort will already be set, and
603 honored when filling the ports message.
606 Job::_CreateAndTransferPorts()
608 // TODO: prefix system ports with "system:"
610 bool defaultPort
= false;
612 for (PortMap::iterator iterator
= fPortMap
.begin();
613 iterator
!= fPortMap
.end(); iterator
++) {
614 BString
name(Name());
615 const char* suffix
= iterator
->second
.GetString("name");
617 name
<< ':' << suffix
;
621 const int32 capacity
= iterator
->second
.GetInt32("capacity",
622 B_LOOPER_PORT_DEFAULT_CAPACITY
);
625 if (suffix
!= NULL
|| fDefaultPort
< 0) {
626 port
= _CreateAndTransferPort(name
.String(), capacity
);
632 } else if (suffix
== NULL
)
635 iterator
->second
.SetInt32("port", port
);
637 if (name
== "x-vnd.haiku-registrar:auth") {
638 // Allow the launch_daemon to access the registrar authentication
639 BPrivate::set_registrar_authentication_port(port
);
643 if (fCreateDefaultPort
&& !defaultPort
) {
645 data
.AddInt32("capacity", B_LOOPER_PORT_DEFAULT_CAPACITY
);
648 if (fDefaultPort
< 0) {
649 port
= _CreateAndTransferPort(Name(),
650 B_LOOPER_PORT_DEFAULT_CAPACITY
);
658 data
.SetInt32("port", port
);
667 Job::_CreateAndTransferPort(const char* name
, int32 capacity
)
669 port_id port
= create_port(B_LOOPER_PORT_DEFAULT_CAPACITY
, Name());
673 status_t status
= set_port_owner(port
, fTeam
);
674 if (status
!= B_OK
) {
684 Job::_Launch(const char* signature
, entry_ref
* ref
, int argCount
,
685 const char* const* args
, const char** environment
)
687 thread_id mainThread
= -1;
688 status_t result
= BRoster::Private().Launch(signature
, ref
, NULL
, argCount
,
689 args
, environment
, &fTeam
, &mainThread
, &fDefaultPort
, NULL
, true);
690 if (result
== B_OK
) {
691 result
= _CreateAndTransferPorts();
693 if (result
== B_OK
) {
694 resume_thread(mainThread
);
696 if (fTeamRegistrator
!= NULL
)
697 fTeamRegistrator
->RegisterTeam(this);
699 kill_thread(mainThread
);
702 _SetLaunchStatus(result
);