Subject: Perl-PVM version 1.1
From: [email-masked] (Edward Walker)
Date: 15 Oct 1996 17:43:38 GMT
Newsgroups: comp.lang.perl.announce,comp.lang.perl.misc

Hi,

	Version 1.1 of Perl-PVM is now available.
This is a perl extension for PVM using dynamic loading.
PVM allows you to write parallel applications over
a heterogenous network of computers.

The differences with 1.0 are as follows:

1, Parallel::Pvm::spawn now accepts argv argument
 
2, Parallel::Pvm::notify accepts "cnt" argument
   for PvmHostAdd
 
3, Parallel::Pvm::recv_notify correctly receives
   list of host tids for PvmHostAdd notification
 
4, Some internal buffering optimization.
 
(1--3 was contributed by Rob Torop. Many thanks
to him!)

You may obtain a copy from my web page

	http://www.nsrc.nus.sg/STAFF/edward/Pvm.html

If you have problems obtaining a copy, get in touch with
me.

I've included a patch file below if you wish to apply 
the patch yourself.  

Enjoy! And may the force be with you.

- ed
---------------------------------------------------------
Dr Edward Walker
National Supercomputing Research Centre
81, Science Park Drive
#04-03, The Chadwick
Singapore 0511

Email: [email-masked]
Web: http://www.nsrc.nus.sg/STAFF/edward

----------------Cut here: 1.0_2_1.1_patch----------------------
*** Pvm.xs
--- Pvm.xs
***************
*** 17,28 ****
   
  #define MAXPROCS	100
  #define MAXHOSTS	100
! #define MAXSTR		200000
  
  #define STRING          1
  #define INTEGER         2
  #define DOUBLE          3
   
  static SV *recvf_callback = (SV *)NULL;
  static int (*olmatch)();
  
--- 17,29 ----
   
  #define MAXPROCS	100
  #define MAXHOSTS	100
! #define MAXSTR		100000
  
  #define STRING          1
  #define INTEGER         2
  #define DOUBLE          3
   
+ static char g_buffer[MAXSTR];
  static SV *recvf_callback = (SV *)NULL;
  static int (*olmatch)();
  
***************
*** 79,85 ****
  {
  int cnt=0;
  
!    cnt = strlen(str);
     /* add 1 for the byte holding the '\0' */
     return cnt+1;
  }
--- 80,88 ----
  {
  int cnt=0;
  
!    while( str[cnt] != '\0' ){
!       cnt++;
!    }
     /* add 1 for the byte holding the '\0' */
     return cnt+1;
  }
***************
*** 100,105 ****
--- 103,115 ----
                  return STRING;
               }
          }
+         /* else{
+              if ( could_be_double ){
+                 if ( str[i] != '0' ){
+                    must_be_double = 1;
+                 }
+              }
+         } */
          i++;
      }
      if ( could_be_double ) return DOUBLE;
***************
*** 109,131 ****
  static char *
  buffer_string( char *str, int new_flag )
  {
! static int bufsize;
! static char *buf ;
   
     if ( new_flag ){
!       bufsize = 1;
!       free(buf);
!       buf = (char *)malloc((strlen(str)+1)*sizeof(char));
!       buf[0] = '\0';
!       bufsize = (strlen(str)+1)*sizeof(char);
!       sprintf(buf,"%s", str );
     }else{
-       bufsize += (strlen(str)+1)*sizeof(char);
-       buf = (char *)realloc(buf,bufsize);
        /* use vertical tab as token separator */
!       sprintf(buf,"%s\v%s",buf, str );
     }
!    return buf ;
  }
  
  /*****/
--- 119,140 ----
  static char *
  buffer_string( char *str, int new_flag )
  {
! static int cnt;
! int i;
   
     if ( new_flag ){
!       cnt=0;
!       for (i=0;str[i] && cnt<MAXSTR-1;i++) g_buffer[cnt++] = str[i];
!       if (cnt == MAXSTR-1) croak("Warning: message truncated. Try increasing MAXSTR");
!       g_buffer[cnt] = '\0';
     }else{
        /* use vertical tab as token separator */
!       g_buffer[cnt++] = '\v';
!       for (i=0;str[i] && cnt<MAXSTR-1;i++) g_buffer[cnt++] = str[i];
!       if (cnt == MAXSTR-1) croak("Warning: message truncated. Try increasing MAXSTR");
!       g_buffer[cnt] = '\0';
     }
!    return g_buffer;
  }
  
  /*****/
***************
*** 684,705 ****
  	int		arg
  
  void
! spawn(task,ntask,flag=PvmTaskDefault,where="")
! 	char *	task
! 	int 	ntask
! 	int 	flag
! 	char *	where
! 	PROTOTYPE: $$;$$
  	PREINIT:
!         int tids[MAXPROCS];
  	int info;
!         int i;
  	PPCODE:
! 	info = pvm_spawn(task,0,flag,where,ntask,tids);
  	XPUSHs(sv_2mortal(newSViv(info)));
  	for (i=0;i<info;i++){
  	   XPUSHs(sv_2mortal(newSViv(tids[i])));
  	}
  	
  int
  initsend(flag=PvmDataDefault)
--- 693,741 ----
  	int		arg
  
  void
! spawn(task,ntask,flag=PvmTaskDefault,where="",argvRef=0)
! 	char *  task
! 	int     ntask
! 	int     flag
! 	char *  where
! 	SV *    argvRef
! 	PROTOTYPE: $$;$$$
  	PREINIT:
! 	int tids[MAXPROCS];
  	int info;
! 	int i;
! 	char ** argv = (char **)0;
  	PPCODE:
!  
! 	if (argvRef)
! 	{
! 	    int   argc;
! 	    AV *  av;
! 	    SV ** a;
!  
! 	    if (!SvROK(argvRef))
! 	        croak("Parallel::Pvm::spawn - non-reference passed for argv");
!  
! 	    av = (AV *) SvRV( argvRef );
! 	    argc = av_len( av ) + 1;        /* number of elts in vector */
! 	    Newz( 0, argv, argc+1, char *); /* last one will be NULL */
!  
! 	    for (i = 0; i < argc; i++)
! 	    {
! 	       if ( a = av_fetch( av, i, 0) )
! 	          argv[i] = (char *) SvPV( *a, na );
! 	    }
! 	}
!  
! 	info = pvm_spawn(task,argv,flag,where,ntask,tids);
!  
! 	Safefree( argv ); /* no harm done if argv is NULL */
!  
  	XPUSHs(sv_2mortal(newSViv(info)));
  	for (i=0;i<info;i++){
  	   XPUSHs(sv_2mortal(newSViv(tids[i])));
  	}
+ 
  	
  int
  initsend(flag=PvmDataDefault)
***************
*** 729,746 ****
  	int i;
  	char *str, *po;
  	CODE:
  	for(i=2;i<items;i++){
! 	   po = (char *)SvPV(ST(i),na);
!            if ( i == 2 ) {
!               str = buffer_string(po,1);
!            } else{
!               str = buffer_string(po,0);
!            }
  	}
- 	if ( items == 2 ){
- 	   str = (char *)malloc(sizeof(char));
- 	   str[0] = '\0';
- 	}
  	RETVAL = pvm_psend(tid,tag,str,string_byte_cnt(str),PVM_BYTE);
  	OUTPUT:
  	RETVAL
--- 765,780 ----
  	int i;
  	char *str, *po;
  	CODE:
+ 	if ( items == 2 )
+ 	   croak("Usage: Parallel::Pvm::pack(@argv)");
  	for(i=2;i<items;i++){
! 	    po = (char *)SvPV(ST(i),na);
!             if ( i == 2 ) {
!                str = buffer_string(po,1);
!             } else{
!                str = buffer_string(po,0);
!             }
  	}
  	RETVAL = pvm_psend(tid,tag,str,string_byte_cnt(str),PVM_BYTE);
  	OUTPUT:
  	RETVAL
***************
*** 878,895 ****
  	int i;
  	char *str, *po;
  	CODE:
          for (i=0;i<items;i++){
! 	   po = (char *)SvPV(ST(i),na);
!            if ( i == 0 ) {
                str = buffer_string(po,1);
!            } else{
                str = buffer_string(po,0);
!            }
  	}
- 	if ( items <= 0 ){
- 	   str = (char *)malloc(sizeof(char));
- 	   str[0] ='\0';
- 	}
          RETVAL = pvm_pkstr(str); 
          OUTPUT:
  	RETVAL
--- 912,927 ----
  	int i;
  	char *str, *po;
  	CODE:
+ 	if ( items <= 0 )
+ 	   croak("Usage: Parallel::Pvm::pack(@argv)");
          for (i=0;i<items;i++){
! 	    po = (char *)SvPV(ST(i),na);
!             if ( i == 0 ) {
                str = buffer_string(po,1);
!             } else{
                str = buffer_string(po,0);
!             }
  	}
          RETVAL = pvm_pkstr(str); 
          OUTPUT:
  	RETVAL
***************
*** 1046,1051 ****
--- 1078,1088 ----
          for (i=0;i<items;i++){
  	    XPUSHs(sv_2mortal(newSViv(infos[i])));
  	}
+ 	/*
+         for (i=0;i<items;i++){
+ 	    free(hosts[i]);
+ 	}
+ 	*/
  
  void
  bufinfo(bufid)
***************
*** 1205,1244 ****
  
  int
  notify(what,tag,...)
! 	int	what
! 	int	tag
  	PROTOTYPE: $$;@
  	PREINIT:
! 	int i, tids[MAXPROCS];
  	CODE:
  	switch(what){
  	   case PvmTaskExit:
  	   case PvmHostDelete:
! 		if ( items < 3 )
! 		   croak("Usage: Parallel::Pvm::pvm_notify(what,tag,tid_list");
!         	for (i=2;i<items;i++){
! 	  	   tids[i-2] = SvIV(ST(i));
! 		}
! 		RETVAL = pvm_notify(what,tag,items-2,tids);
! 		break;
  	   case PvmHostAdd:
! 		RETVAL = pvm_notify(what,tag,0,tids);
! 		break;
  	}
  	OUTPUT:
  	RETVAL
  
  int
! recv_notify()
! 	PROTOTYPE:
  	PREINIT:
! 	int id;
! 	CODE:
  	pvm_recv(-1,-1);
! 	pvm_upkint(&id,1,1);
! 	RETVAL = id;
! 	OUTPUT:
! 	RETVAL
  
  void
  hostsync(hst)
--- 1242,1298 ----
  
  int
  notify(what,tag,...)
! 	int     what
! 	int     tag
  	PROTOTYPE: $$;@
  	PREINIT:
! 	int i, cnt, tids[MAXPROCS];
  	CODE:
  	switch(what){
  	   case PvmTaskExit:
  	   case PvmHostDelete:
! 	        if ( items < 3 )
! 	           croak("Usage: Parallel::Pvm::pvm_notify(what,tag,tid_list");
! 	        for (i=2;i<items;i++){
! 	           tids[i-2] = SvIV(ST(i));
! 	        }
! 	        RETVAL = pvm_notify(what,tag,items-2,tids);
! 	        break;
  	   case PvmHostAdd:
! 	        if ( items < 2 )
! 	          croak("Usage:  Parallel::Pvm::pvm_notify(PvmHostAdd,tag [,cnt]");
! 	        if (2 == items )
! 	        cnt = -1;
! 	        else
! 	           cnt = SvIV(ST(2));
! 	        RETVAL = pvm_notify(what,tag, cnt, (int *)0 );
! 	        break;
  	}
  	OUTPUT:
  	RETVAL
  
  int
! recv_notify(what)
! 	int what
! 	PROTOTYPE: $
  	PREINIT:
! 	int id,i,cnt;
! 	int tids[MAXPROCS];
! 	PPCODE:
  	pvm_recv(-1,-1);
! 	switch (what )
! 	{
! 	   case PvmTaskExit:
! 	   case PvmHostDelete:
! 	        pvm_upkint(&id,1,1);
! 	        XPUSHs( sv_2mortal(newSViv(id)) );
! 	        break;
! 	   case PvmHostAdd:
! 	        pvm_upkint( &cnt, 1, 1 );
! 	        pvm_upkint( tids, cnt, 1 );
! 	   for ( i=0; i < cnt; i++)
! 	       XPUSHs(sv_2mortal(newSViv(tids[i])));
! 	}
  
  void
  hostsync(hst)
*** Pvm.pm
--- Pvm.pm
***************
*** 93,99 ****
  	PvmTraceTid
  );
  
! $VERSION = '1.0';
  
  sub AUTOLOAD {
      # This AUTOLOAD is used to 'autoload' constants from the constant()
--- 93,99 ----
  	PvmTraceTid
  );
  
! $VERSION = '1.1';
  
  sub AUTOLOAD {
      # This AUTOLOAD is used to 'autoload' constants from the constant()
***************
*** 348,354 ****
  For more sophisticated users, B<Parallel::Pvm::spawn> may be given additional 
  argument parameters to control how/where you want a task to be spawned.
  For example, you can specifically spawn B<client> in the internet 
! host <onyx.nsrc.nus.sg> by calling
  
  	Parallel::Pvm::spawn("client",1,PvmTaskHost,"onyx.nsrc.nus.sg");
  
--- 348,354 ----
  For more sophisticated users, B<Parallel::Pvm::spawn> may be given additional 
  argument parameters to control how/where you want a task to be spawned.
  For example, you can specifically spawn B<client> in the internet 
! host B<onyx.nsrc.nus.sg> by calling
  
  	Parallel::Pvm::spawn("client",1,PvmTaskHost,"onyx.nsrc.nus.sg");
  
***************
*** 357,362 ****
--- 357,367 ----
  
  	Parallel::Pvm::spawn("client",4,PvmTaskArch,"RS6K");
  
+ Also, if the spawned remote executable requires an argument B<argv>, 
+ you can supply this by calling
+ 
+ 	Parallel::Pvm::spawn("client",4,PvmTaskArch,"RS6K",argv);
+ 
  Note that tasks which have been spawned by using B<Parallel::Pvm::spawn> 
  do not need to be explicitly enrolled into the pvm system.  
  
***************
*** 662,667 ****
--- 667,678 ----
  
  	$info = Parallel::Pvm::notify(PvmHostDelete,999,$host_list);
  
+ 	# turns on notification for new host
+ 	$info = Parallel::Pvm::notify(PvmHostAdd);
+ 
+         # turns off notification for new host
+ 	$info = Parallel::Pvm::notify(PvmHostAdd,0);
+ 
  =item B<Parallel::Pvm::nrecv>
  
  Nonblocking receive.  Eg.
***************
*** 753,762 ****
  Receives the notification message initiated by B<Parallel::Pvm::notify>.  This 
  should be preceded by a B<Parallel::Pvm::probe>.  Eg.
  
  	if ( Parallel::Pvm::probe(-1,$notify_tag) ){
! 		$message = Parallel::Pvm::recv_notify ;
  	}
  
  =item B<Parallel::Pvm::recvf_old>
  
  Resets the comparison function for accepting messages to the 
--- 764,777 ----
  Receives the notification message initiated by B<Parallel::Pvm::notify>.  This 
  should be preceded by a B<Parallel::Pvm::probe>.  Eg.
  
+ 	# for PvmTaskExit and PvmHostDelete notification
  	if ( Parallel::Pvm::probe(-1,$notify_tag) ){
! 		$message = Parallel::Pvm::recv_notify(PvmTaskExit) ;
  	}
  
+ 	# for PvmHostAdd notification
+ 	@htid_list = Parallel::Pvm::recv_notify(PvmHostAdd);
+ 
  =item B<Parallel::Pvm::recvf_old>
  
  Resets the comparison function for accepting messages to the 
***************
*** 829,834 ****
--- 844,851 ----
  	($ntask,@tid_list) = Parallel::Pvm::spawn("compute.pl",4);
  
  	($ntask,@tid_list) = Parallel::Pvm::spawn("compute.pl",4,PvmTaskHost,"onyx");
+ 
+ 	($ntask,@tid_list) = Parallel::Pvm::spawn("compute.pl",4,PvmTaskHost,"onyx",argv);
  
  =item B<Parallel::Pvm::tasks>