Problems understanding and implementing process management

J

James Calivar

Hello,

I'm a pretty new Perl programmer, and am having some difficulty in finding
the correct way to approach process management in an application that I'm
writing. Basically, I've written a Perl/Tk script that pops up a nice GUI
that a user can use to configure some parameters, and then press a Start
button to kick off a separate (already written and tested) Perl script.
This secondary Perl script is something that I want to have run as a
separate process from the GUI script, and it does its own thing in the
background. I want to be able to terminate the secondary script at any time
by pressing a Stop button, with the result that the secondary process is
terminated but the GUI remains up so that the process can be kicked off
again is desired.

I'm running ActiveState Perl 5.8.4 on a Windows XP machine (SP2).

Now, I've been somewhat successful in invoking the secondary script by using
one of a couple of different methods. But I'm not sure which one is really
appropriate for my application. The first thing I did was to just try to
use the system() command - but this waits for the secondary process to
terminate before the GUI proceeds, the net effect being that when I press
the Start button, the GUI essentially hangs up (with the button depressed)
and only recovers after I kill the secondary script with Ctrl-C. (I do not
want to use the exec() function, because that terminates the GUI.) I also
tried using fork(), but every time I invoke it, the script crashes and gives
me the "Windows has encoutered a problem - would you like to file a report?"
error message. So it seems that fork() is out. Finally, I tried using
piped processes (as suggested in Learning Perl, Chapter 14 "Processes as
Filehandles"). That also kicks off my secondary script, and returns control
over the GUI to me, but now I cannot terminate the secondary process. And I
believe it's because, as with the system() call, the close command issued to
the filehandle that I have assigned to the secondary process also has to
wait for that process to terminate, which it won't - so again, I'm stuck.

Can anyone here kindly nudge me in the right direction? Am I on the right
track, or do I need to switch methods altogether? I can provide code
examples if need be.

Thanks

James
 
A

Ala Qumsieh

James said:
Hello,

I'm a pretty new Perl programmer, and am having some difficulty in finding
the correct way to approach process management in an application that I'm
writing. Basically, I've written a Perl/Tk script that pops up a nice GUI

What GUI library are you using? If Tk, then perhaps you can use the
Tk::fileevent method, as described in its pods.
that a user can use to configure some parameters, and then press a Start
button to kick off a separate (already written and tested) Perl script.

What does the second script do? Is there any data that needs to be
passed back to the GUI?
I'm running ActiveState Perl 5.8.4 on a Windows XP machine (SP2).

Now, I've been somewhat successful in invoking the secondary script by using
one of a couple of different methods. But I'm not sure which one is really
appropriate for my application. The first thing I did was to just try to
use the system() command - but this waits for the secondary process to
terminate before the GUI proceeds, the net effect being that when I press
the Start button, the GUI essentially hangs up (with the button depressed)
and only recovers after I kill the secondary script with Ctrl-C. (I do not

I believe on Windows, you can use the command "start prog.pl" to run
your second Perl script in the background.
want to use the exec() function, because that terminates the GUI.) I also
tried using fork(), but every time I invoke it, the script crashes and gives
me the "Windows has encoutered a problem - would you like to file a report?"
error message. So it seems that fork() is out. Finally, I tried using

The perlfork pods claim:

On some platforms such as Windows where the fork() system call is not
available, Perl can be built to emulate fork() at the interpreter
level.

Which Win32 Perl distribution are you using?
piped processes (as suggested in Learning Perl, Chapter 14 "Processes as
Filehandles"). That also kicks off my secondary script, and returns control
over the GUI to me, but now I cannot terminate the secondary process. And I

Can you show this code?

If you use open() to create your pipe, then the return value of your
open is the pid of your child process. You can use that to kill() it.

--Ala
 
J

James Calivar

Ala Qumsieh said:
GUI

What GUI library are you using? If Tk, then perhaps you can use the
Tk::fileevent method, as described in its pods.

Tk is what I'm using. The GUI part is all done; it's just this last one
command that kicks off another process that is driving me nuts.
What does the second script do? Is there any data that needs to be
passed back to the GUI?

Well, in the *real* application, the secondary script does a lot of stuff.
But as far as the calling GUI code is concerned, it does nothing - it just
goes out and stays out and needs to be killed off at some point via some
method yet to be determined. So, for the purposes of testing, I've just
replaced it with a script that prints out the "spinning text wheel" either
for 30 seconds or so, or (optionally if I uncomment out the commented
lines), forever. This kind of emulates a long-lived process. And since it
won't ever return/terminate (at least not immediately), I can't use
system(), exec() or the "piped process" method since all of those methods
must wait for the secondary application's termination before they can
proceed.
not

I believe on Windows, you can use the command "start prog.pl" to run
your second Perl script in the background.

Do you mean system()?
The perlfork pods claim:

On some platforms such as Windows where the fork() system call is not
available, Perl can be built to emulate fork() at the interpreter
level.

Which Win32 Perl distribution are you using?

Win XP Pro, running Perl ActiveState Perl 5.8.7 (Build 813) - I just
upgraded.
And I

Can you show this code?

If you use open() to create your pipe, then the return value of your
open is the pid of your child process. You can use that to kill() it.

--Ala

Here is the code, stripped down somewhat so that noone has to look at all
the meaningless parts. There are two files: daemon_gui.pl, and test2.pl.
daemon_gui.pl is the Tk-enabled "master" code that sets up the GUI
environment, and kicks off the secondary file (test2.pl) when the "Start
Daemon" button is pressed. As you can see, test2.pl is simply a stub that
"spins its wheels" in the command-line window that daemon_gui.pl is invoked
from (I always like to start the script from a CLI when developing, because
then I can see messages that I would lose if I just double-clicked the file
in Windows Explorer).

So basically, if you invoke daemon_gui.pl (from CLI), the click the Start
button, you'll see the "spinning text" in the CLI. Now what I *want* to
happen is when I press Stop, the secondary script is terminated immediately.
But what is *actually* happening is that the Stop button's actions do not go
into effect until the secondary script has stopped processing.

Some rudimentary debug code in daemon_gui.pl (lines 118 and 129) show me
that the process ID that I am attempting to kill is the same one created
when I invoke the secondary script. Do I need to embed a signal handler
routine in the secondary script or something?

Any ideas, comments, questions, etc?

Thanks for your help

James Calivar

daemon_gui.txt:
==========
#---------------------------#
# initial environment setup
#---------------------------#
use Tk;
use Tk::widgets qw/Dialog/;
use Tk::Balloon;
use subs qw/buildMenuBar finishUp startDaemon stopDaemon/;
use vars qw/$MW $VERSION $pid/;
use strict;

############################################################################
##############
# BEGIN Variable Declarations
#---------------------------------------------------------------------------
-------------#

# version number for internal tracking
$VERSION = '0.97';

#-----------------------------------------------#
# hash used to hold values for all config params
#-----------------------------------------------#
my %config = (
"dbpwd" => undef
);

my @hash_keys = keys %config;
my @hash_vals = values %config;

#-----------------------------------------------#
# hash used to hold popup balloon text msgs
#-----------------------------------------------#
my %configMessages = (
"dbpwd" => "Password for database user account (hidden when typed on
screen)"
);

#-----------------------------------------------#
# hash used to hold handles to Entry widgets
#-----------------------------------------------#
my %configEntry;

#---------------------------------------------------------------------------
-------------#
# END Declarations
############################################################################
##############

############################################################################
##############
# BEGIN Main window geometry setup
#---------------------------------------------------------------------------
-------------#

#-------------------------------------#
# define the main window's attributes
#-------------------------------------#
$MW = MainWindow->new;
$MW->geometry("520x540+0+0");
$MW->title("Daemon GUI $VERSION");
my $menubar = buildMenuBar;

#-------------------------------------------------#
# set up conf.ini variable labels and entry boxes
#-------------------------------------------------#
my $startButton = $MW->Button (-text => "Start Daemon\n", -anchor => 'n',
-foreground => 'black',
-background => 'SeaGreen3',
-activeforeground => 'black',
-activebackground => 'green',
-command => sub {startDaemon})
->place(-anchor=>'nw', -x=>325, -y=>467);

my $stopButton = $MW->Button (-text => "Stop Daemon\n", -anchor => 'n',
-foreground => 'black',
-background => 'salmon1',
-activeforeground => 'white',
-activebackground => 'red',
-command => sub {stopDaemon})
->place(-anchor=>'nw', -x=>425, -y=>467);

my $idx = 0;
foreach my $key (@hash_keys)
{
# draw a label widget that annotates the variable being entered
my $label = $MW->Label(-text => "$key:\n")->place(-anchor =>
'nw', -x=>0, -y=>(10 + $idx*25));

# draw a popover balloon that describes the label widget
my $balloon = $MW->Balloon(-state => 'balloon');
$balloon->attach($label, -balloonmsg => $configMessages{$key}, -initwait
=> 10,
-balloonposition => 'mouse', -state => 'balloon');

# draw an entry widget that accepts input for the variable being entered
# special case for password, which should show up as asteriks
if ($key eq 'dbpwd')
{
$configEntry{$key} = $MW->Entry(-textvariable => \$config{$key}, -show
=> '*')
->place(-anchor=>'nw', -x=>150, -y=>(1
0 + $idx*25));
}
else
{
$configEntry{$key} = $MW->Entry(-textvariable => \$config{$key})
->place(-anchor=>'nw', -x=>150, -y=>(1
0 + $idx*25));
}
$idx++;
}

#---------------------------------------------------------------------------
-------------#
# END Main window geometry setup
############################################################################
##############

############################################################################
##############
# BEGIN Subroutine Definitions
#---------------------------------------------------------------------------
-------------#

#--------------------------------------#
# Start the daemon if all config values
# have been filled out; look for config
# file first, then check entries in GUI
#--------------------------------------#
sub startDaemon {

# kick off daemon
$pid = open DAEMON, "|perl test2.pl";
print ("Process ID created is $pid\n");

} # end startDaemon()

#--------------------------------------#
# commit the changes to the conf file
# (this will be a lot cleaner with the
# config hash)
#--------------------------------------#
sub stopDaemon {

print ("Process ID to kill is $pid\n");
kill 2, $pid or die "Cannot signal $pid with SIGINT: $!";
close DAEMON;

} # end stopDaemon()

#---------------------------------#
# build up the GUI's menu structure
#---------------------------------#
sub buildMenuBar {

# Create the menubar, and File and Quit menubuttons. Note
# that the cascade's menu widget is automatically created.
my $menubar = $MW->Menu;
$MW->configure(-menu => $menubar);
my $file = $menubar->cascade(-label => '~File', -tearoff => 0);
my $help = $menubar->cascade(-label => '~Help', -tearoff => 0);

# Create the menuitems for each menu. First, the File menu item.
$file->command(-label => "Open...", -command => \&open);
$file->separator;
$file->command(-label => "Save...", -command => \&save);
$file->separator;
$file->command(-label => "Quit", -command => \&finishUp);

# Help menuitems (Version and About)
$help->command(-label => 'Version');
$help->separator;
$help->command(-label => 'About');

my $ver_dialog = $MW->Dialog(-title => 'Daemon GUI Utility',
-font=> "Arial 10 normal",
-text=> "Daemon GUI Utility Version
$VERSION",
-buttons => ['OK'],
-bitmap => 'info');

my $about_dialog = $MW->Dialog(-title => 'About Daemon GUI Utility',
-font=> "Arial 10 normal",
-text=> "Daemon GUI Utility Version
$VERSION\n\n\Copywright 2005\n\nDaemon GUI Enterprises, Inc. (LLC)\n\nUse
without explicit permission is strictly prohibited. Violators will be
prosecuted to the fullest extent of the law.",
-buttons => ['OK']);

my $menu = $help->cget('-menu');
$menu->entryconfigure('Version', -command => [$ver_dialog => 'Show']);
$menu->entryconfigure('About', -command => [$about_dialog => 'Show']);

# return the menubar
$menubar;

} # end buildMenuBar()

#--------------------------------------------------#
# retrieve GUI configuration from earlier sessions
#--------------------------------------------------#
sub open {

} # end open()

#--------------------------------------#
# save GUI configuration for later use
#--------------------------------------#
sub save {

} # end save()

#-------------------------------#
# Clean up and exit the program
#-------------------------------#
sub finishUp {

exit;

} # end finishUp()

#---------------------------------------------------------------------------
-------------#
# END Subroutine Definitions
############################################################################
##############

############################################################################
##############
# BEGIN Main Event Processor Loop
#---------------------------------------------------------------------------
-------------#

MainLoop;

#---------------------------------------------------------------------------
-------------#
# END Main Event Processor Loop
############################################################################
##############

test2.pl:
=====
use strict;

my $i = 0;
# while (1) {
for ($i = 0; $i <= 2000000; $i++) {
if (($i % 4) == 0) {
print "|\r";
} elsif (($i % 4) == 1) {
print "/\r";
} elsif (($i % 4) == 2) {
print "-\r";
} else {
# $i = 0;
print "\\\r";
}
# $i++;
}
 
A

A. Sinan Unur

Here is the code,

Please make an effort not to use extra comment lines that wrap when
pasted, and format you source code nicely. Consider running it through a
code beautifier even if you are not willing to follow the recommendations
given in perldoc perlstyle.

I have been trying to run your code for the last 15 minutes, but it won't
due to various problems.

Sinan
 
A

Ala Qumsieh

James said:
Tk is what I'm using. The GUI part is all done; it's just this last one
command that kicks off another process that is driving me nuts.

Ok, I can suggest two ways to proceed:

1. Use Tk::fileevent. I have done exactly the same thing before, but
it's a bit tedious since you have to keep track of many things.

2. Use Tk::ExecuteCommand (available from CPAN) that is just a nice
wrapper around Tk::fileevent that allows you to do cool things like:

$ec = $mw->ExecuteCommand(...)->pack;
$ec->execute_command;
$ec->kill_command;

I would go with #2.

--Ala
 
A

A. Sinan Unur

OK - did I exceed some magic column number?

I am not sure if it is magic, but I hope you can see the problem with

#-----------------------------------------------------------------------
-----------------#

which is 90 characters wide.
What is a code beautifier?

See said:
....
Can you tell me what are the "various problems"?

Well, when you have lines like the one above, perl does not just say,
oh, the line was too long, it just spilled over to the next line, and
created some weird thing. It says:

Number found where operator expected at D:\Home\gui.pl line
102, near "0"
(Missing semicolon on previous line?)
Number found where operator expected at D:\Home\gui.pl line
108, near "0"
(Missing semicolon on previous line?)
Can't modify negation (-) in predecrement (--) at D:\Home\gui.pl line
18, near "$VERSION ="
syntax error at D:\Home\gui.pl line 102, near "0"
syntax error at D:\Home\gui.pl line 108, near "0"
syntax error at D:\Home\gui.pl line 130, near "sub startDaem
on "
syntax error at D:\Home\gui.pl line 136, near "}"
Execution of D:\Home\gui.pl aborted due to compilation errors.

Then, it is not clear at first sight, what is causing these problems.
Then, after some time, I realized the long, vanity comments. At that
point, I had no more motivation to try anything.

I am glad Ala was able to help you (and I learned something from his
post). But the next time, I won't even see your post.

Sinan
 
J

Joe Smith

James said:
because I had a comment line that exceeded 80
lines ??? For the record, my perl executable didn't puke on this.

Have you actually tested that? To properly test it, you'll need to
have to the code as we received it, which is different from what
you started with.

Go back to
Date: Fri, 8 Jul 2005 15:36:31 -0400
Message-ID: <[email protected]>
select the text and copy-and-paste it into a new file. Then check
to see if your perl executable barfs on that.

I expect that you'll see the same thing we see: overly long comments
got mangled by the trip to USENET and back. If you can't get
the program to work after copy-and-paste, neither can we.
-Joe
 
T

Tad McClellan

James Calivar said:
??? You're *killfiling me* because I had a comment line that exceeded 80
lines ???


No, the "disease" is that you did not make it easy for us to help you.

The "symptom" was posting code that we could not copy/paste and run.

The line-wrapping of the overly long comments (probably done by your
news posting client) made the code not even compile, let alone run.

For the record, my perl executable didn't puke on this.


Then your "this" is not our "this".

We don't have your code. All we have is the code you showed us.

Have you tried running the actual code that you showed us? (rhetorical question)

I guess ActiveState''s perl is at
least smart enough to know that a comment should be treated as such.


You sure look silly now.

Thanks for not helping,


Glad to join in and oblige.

*plonk*
 
S

Sherm Pendley

James Calivar said:
Christ you people sure are intolerant. Enjoy your limited view of the
Perl world, fucktard.

I didn't killfile you before, but I certainly will now.

*plonk*

sherm--
 
T

Tad McClellan

James Calivar said:
Christ you people sure are intolerant.


The code would not compile, you insisted it would compile, we are
intolerant of the possibility of impossible things happening.

Such intolerance is common even outside of this newsgroup.

Enjoy your limited view of the
Perl world,


Most people would have apologized for the broken code, fixed it,
and gotten some help with it.

It appears you are not such a person.

(and, since the code would not compile, it was NOT a member of the
set comprising the "Perl world".
)

fucktard.


I love you too.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,767
Messages
2,569,571
Members
45,045
Latest member
DRCM

Latest Threads

Top