def _allocate_popsno(): """ allocate pops number In order to prevent multiple AIPS instances from using the same POPS number, every AIPS instance creates a lock file in /tmp. These lock files are named AIPSx.yyy, where x is the POPS number (in extended hex) and yyy is the process ID of the AIPS instance. Create a file in /tmp/AIPS_pops.pid to indicate this pops number is in use. """ for popsno in range(1, 16): # In order to prevent a race, first create a lock file for # POPSNO. try: path = '/tmp/AIPS' + ehex(popsno, 1, 0) + '.' + str(os.getpid()) fd = os.open(path, os.O_WRONLY | os.O_CREAT | os.O_EXCL, 0o644) os.close(fd) except: continue # Get a list of likely lock files and iterate over them. # Leave out our own lock file though. files = glob.glob('/tmp/AIPS' + ehex(popsno, 1, 0) + '.[0-9]*') files.remove(path) for file in files: # If I can't write it is probably not mine if not os.access(file, os.W_OK): #print "DEBUG write access failed for ",file break # If the part after the dot isn't an integer, it's not a # proper lock file. try: pid = int(file.split('.')[1]) except: continue # Check whether the AIPS instance is still alive. try: os.kill(pid, 0) except: # The POPS number is no longer in use. Try to clean # up the lock file. This might fail though if we # don't own it. try: os.unlink(file) except: pass else: # The POPS number is in use. break else: # The POPS number is still free. return popsno # Clean up our own mess. os.unlink(path) raise RuntimeError("No free AIPS POPS number available on this system")
def _free_popsno(popsno): """ Deallocate pops number Unlinks /tmp/ObitScript_pops file """ path = '/tmp/ObitScript' + ehex(popsno, 1, 0) + '.' + str(os.getpid()) os.unlink(path)
def messages(self, tid): """Return task's messages. Return a list of messages each as a tuple (1, message) tid = Task id in pid table of process """ # Make sure we read the messages, even if we throw them away # later to prevent the task from blocking. messages = Task.messages(self, tid) #print "Raw",messages # Check that tid in bounds #if tid>len(self._popsno): # print "DEBUG Proxy/AIPSTask", messages, tid, len(self._popsno) # return messages # Convert into list of lines tmessage = [] for msg in messages: lmess = msg.splitlines(True) for mm in lmess: tmessage.append(mm) # Strip out all formal messages. start = '%-5s%d' % (self._params[tid].name.upper(), self._popsno[tid]) lmessages = [msg for msg in tmessage if msg.startswith(start)] #print "Filtered",lmessages pmessages = [msg for msg in tmessage if not msg.startswith(start)] #print "Print",pmessages # These messages will be looked up in the AIPS message log #messages = [(1, msg) for msg in lmessages] messages = [] user = ehex(self._userno[tid], 3, 0) ms_name = os.environ['DA01'] + '/MS' + AIPS.revision \ + user + '000.' + user + ';' ms_file = open(ms_name, mode='r') (msgno,) = struct.unpack('i', ms_file.read(4)) while self._msgno[tid] < msgno: (task, popsno, priority, msg) = \ self.__read_message(ms_file, self._msgno[tid]) # Filter if popsno == self._popsno[tid]: messages.append((priority, '%-5s%d: %s\n' % (task, popsno, msg))) pass self._msgno[tid] += 1 continue ms_file.close() # Add "print" messages if len(pmessages)>0: for msg in pmessages: messages.append((1,msg)) #print "returned messages",messages return messages
def spawn(self, name, version, userno, msgkill, isbatch, input_dict): """Start the script.in an externak ObitTalk Writes script test into temporary file in /tmp and executes ObitTalk asynchronously returning immediately. Messages must be retrieved calling messages. name script name version version of any AIPS tasks userno AIPS user number msgkill AIPStask msgkill level, isbatch True if this is a batch process input_dict Input info as dictionary Returns script id """ popsno = _allocate_popsno() index = popsno - 1 self.name = name self.userno = userno try: # Construct the environment for the script. # Set AIPS and FITS directory variables env = os.environ.copy() # AIPS directories i = 0 for dirname in input_dict["AIPSDirs"]: i = i+1 area = 'DA' + ehex(i, 2, '0') env[area] = dirname # end AIPS dirs # FITS directories i = 0 for dirname in input_dict["FITSDirs"]: i = i+1 if i==1: area = "FITS" else: area = 'FITS' + ehex(i, 2, '0') env[area] = dirname # End FITS Dirs # print "script environment",env # print "PYTHONPATH",env["PYTHONPATH"] # Script text file sc_name = "/tmp/" + name+ "Script." + str(popsno)+".py" # Write script to file self.__write_script (self.name, userno, popsno, sc_name, input_dict) # If debugging add a link to the input file to preserve it. if input_dict['debug']: tmpDebug = "/tmp/" + name+ "Script." + str(popsno)+"Dbg.py" if os.access(tmpDebug, os.F_OK): os.unlink(tmpDebug) # Remove any old version file. os.link(sc_name, tmpDebug) # Add new link. # Tell about it. print("Saving copy of Obit task input in " + tmpDebug) # Start script in separate ObitTalk process. path = 'ObitTalk' tid = Task.spawn(self, path, ["ObitTalk", sc_name], env) except Exception as exception: _free_popsno(popsno) raise exception self._popsno[tid] = popsno self._userno[tid] = userno self._msgkill[tid] = msgkill self._msgno[tid] = 0 return tid
def _open(self, userno): user = ehex(userno, 3, 0) ms_name = os.environ['DA01'] + '/MS' + AIPS.revision \ + user + '000.' + user + ';' return open(ms_name, mode='r+')
def spawn(self, name, version, userno, msgkill, isbatch, input_dict): """Start the task. Writes task input parameters in theTD file and starts the task asynchronously returning immediately. Messages must be retrieved calling messages. Attempts to use singel hardcoded AIPS TV name task name version version of task userno AIPS user number msgkill AIPS msgkill level, isbatch True if this is a batch process input_dict Input parameters as dictionary Returns task id """ params = _AIPSTaskParams(name, version) popsno = _allocate_popsno() index = popsno - 1 try: # A single hardcoded TV will do until support for multiple # TVs is implemented. ntvdev = 1 # Construct the environment for the task. For the 'infile', # 'outfile' and 'outprint' adverbs, we split off the directory # component of the pathname and use that as the area. env = os.environ.copy() area = 'a' for adverb in self._file_adverbs: if adverb in input_dict: assert (ord(area) <= ord('z')) dirname = os.path.dirname(input_dict[adverb]) if dirname: if not os.path.isdir(dirname): msg = "Directory '%s' does not exist" % dirname raise RuntimeError(msg) env[area] = dirname basename = os.path.basename(input_dict[adverb]) input_dict[adverb] = area + ':' + basename area = chr(ord(area) + 1) pass pass continue # Send output to the TV running on this machine. env['TVDEV' + ehex(ntvdev, 2, 0)] = 'sssin:localhost' # DEBUG #print "aips environment",env td_name = os.environ['DA00'] + '/TD' + AIPS.revision + '000004;' td_file = open(td_name, mode='r+b') td_file.seek(index * 20) td_file.write( struct.pack('8s', six.ensure_binary(name.upper().ljust(8)))) td_file.write(struct.pack('l', -999)) td_file.write(struct.pack('2l', 0, 0)) td_file.seek(1024 + index * 4096) td_file.write(struct.pack('i', userno)) td_file.write(struct.pack('i', ntvdev)) td_file.write(struct.pack('i', 0)) td_file.write(struct.pack('i', msgkill + 32000 - 1)) td_file.write(struct.pack('i', isbatch)) td_file.write(struct.pack('i', 0)) td_file.write(struct.pack('2i', 0, 0)) td_file.write(struct.pack('f', 1.0)) td_file.write(struct.pack('4s', b' ')) for adverb in params.input_list: self.__write_adverb(params, td_file, adverb, input_dict[adverb]) continue td_file.close() # Pass aips directories i = 0 for dir in input_dict["AIPSdirs"]: i += 1 daname = "DA" + ehex(i, 2, 0) if not name in env: env[daname] = dir # Create the message file if necessary and record the # number of messages currently in it. user = ehex(userno, 3, 0) if 'DA01' in os.environ: # Use DA01 from environment if given da01 = os.environ['DA01'] else: # Else from AIPSdirs passed. da01 = input_dict["AIPSdirs"][0] # Grumble, grumble os.environ['DA01'] = da01 cmd = "export DA01=" + da01 # shell environment z = os.system(cmd) ms_name = da01 + '/MS' + AIPS.revision \ + user + '000.' + user + ';' if not os.path.exists(ms_name): ms_file = open(ms_name, mode='w') ms_file.truncate(1024) ms_file.close() os.chmod(ms_name, 0o664) pass ms_file = open(ms_name, mode='rb') (msgno, ) = struct.unpack('i', ms_file.read(4)) ms_file.close() path = params.version + '/' + os.environ['ARCH'] + '/LOAD/' \ + name.upper() + ".EXE" tid = Task.spawn(self, path, [name.upper() + str(popsno)], env) except Exception as exception: _free_popsno(popsno) raise exception self._params[tid] = params self._popsno[tid] = popsno self._userno[tid] = userno self._msgkill[tid] = msgkill self._msgno[tid] = msgno return tid