Interpreter.cpp
Go to the documentation of this file.
1 /*----------------------------------------------------------------------------*/
2 /* */
3 /* Copyright (c) 1995, 2004 IBM Corporation. All rights reserved. */
4 /* Copyright (c) 2005-2009 Rexx Language Association. All rights reserved. */
5 /* */
6 /* This program and the accompanying materials are made available under */
7 /* the terms of the Common Public License v1.0 which accompanies this */
8 /* distribution. A copy is also available at the following address: */
9 /* http://www.ibm.com/developerworks/oss/CPLv1.0.htm */
10 /* */
11 /* Redistribution and use in source and binary forms, with or */
12 /* without modification, are permitted provided that the following */
13 /* conditions are met: */
14 /* */
15 /* Redistributions of source code must retain the above copyright */
16 /* notice, this list of conditions and the following disclaimer. */
17 /* Redistributions in binary form must reproduce the above copyright */
18 /* notice, this list of conditions and the following disclaimer in */
19 /* the documentation and/or other materials provided with the distribution. */
20 /* */
21 /* Neither the name of Rexx Language Association nor the names */
22 /* of its contributors may be used to endorse or promote products */
23 /* derived from this software without specific prior written permission. */
24 /* */
25 /* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS */
26 /* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT */
27 /* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS */
28 /* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT */
29 /* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, */
30 /* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED */
31 /* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */
32 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY */
33 /* OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */
34 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS */
35 /* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */
36 /* */
37 /*----------------------------------------------------------------------------*/
38 /*****************************************************************************/
39 /* REXX Windows Support */
40 /* */
41 /* Main interpreter control. This is the preferred location for all */
42 /* platform independent global variables. */
43 /* The interpreter does not instantiate an instance of this */
44 /* class, so most variables and methods should be static. */
45 /* */
46 /* */
47 /*****************************************************************************/
48 
49 #include "Interpreter.hpp"
50 #include "ActivityManager.hpp"
51 #include "ListClass.hpp"
52 #include "SystemInterpreter.hpp"
53 #include "InterpreterInstance.hpp"
54 #include "DirectoryClass.hpp"
55 #include "ProtectedObject.hpp"
56 #include "RexxInternalApis.h"
57 #include "PackageManager.hpp"
58 
59 
60 // global resource lock
61 SysMutex Interpreter::resourceLock("Interpreter::resourceLock");
62 
64 
65 // the local server object
67 
68 // the interpreter active state flag
69 bool Interpreter::active = false;
70 // used for timeslice dispatching
72 
73 
74 /**
75  * Initialize the interpreter subsystem.
76  */
78 {
80 }
81 
82 
83 void Interpreter::live(size_t liveMark)
84 {
88 }
89 
90 void Interpreter::liveGeneral(int reason)
91 {
93  {
97  }
98 }
99 
101 {
102  // the locks get create in order
103  createLocks();
106  // make sure we have a session queue created for this process
107 }
108 
110 {
111  // we destroy the locks in reverse order
114  closeLocks();
115 }
116 
117 
118 /**
119  * Perform interpreter startup processing.
120  *
121  * @param mode The startup mode. This indicates whether we're saving the
122  * image or in shutdown mode.
123  */
124 void Interpreter::startInterpreter(InterpreterStartupMode mode, const char *imageTarget)
125 {
126  ResourceSection lock("Interpreter::startInterpreter", 0);
127 
128  // has everything been shutdown?
129  if (!isActive())
130  {
131  SystemInterpreter::startInterpreter(); // perform system specific initialization
132  // initialize the memory manager , and restore the
133  // memory image
134  memoryObject.initialize(mode == RUN_MODE, imageTarget);
136  // create our instances list
138  // if we have a local server created already, don't recurse.
139  if (localServer == OREF_NULL)
140  {
141  // Get an instance. This also gives the root activity of the instance
142  // the kernel lock.
143  InstanceBlock instance;
144  /* get the local environment */
145  /* get the server class */
146  RexxObject *server_class = env_find(new_string("!SERVER"));
147 
148  // NOTE: This is a second block so that the
149  // protected object's destructor gets run before
150  // the activity is removed as the current activity.
151  {
152  ProtectedObject result;
153  /* create a new server object */
154  server_class->messageSend(OREF_NEW, OREF_NULL, 0, 0, result);
155  localServer = (RexxObject *)result;
156  }
157  }
158  }
159  // we're live now
160  active = true;
161 }
162 
163 
164 /**
165  * Initialize an instance .local object.
166  */
168 {
169  // only do this if the local server has already been created.
170  if (localServer != OREF_NULL)
171  {
172  // this will insert the initial .local objects
173  ProtectedObject result;
174  localServer->messageSend(OREF_INITINSTANCE, OREF_NULL, 0, 0, result);
175  }
176 }
177 
178 
179 /**
180  * Terminate the global interpreter environment, shutting down
181  * all of the interpreter instances that we can and releasing
182  * the object heap memory.
183  *
184  * @return true if everything was shutdown, false if there are reasons
185  * why this can't be shutdown.
186  */
188 {
189  {
190  ResourceSection lock("Interpreter::terminateInterpreter", 0); // lock in this section
191  // if never even started up, then we've got a quick return
192  if (!isActive())
193  {
194  return true;
195  }
196 
197  // we can only shutdown interpreter instances from the
198  // threads that created them. If we have active instances,
199  // this is a "no can do" situation
200  if (interpreterInstances->items() != 0)
201  {
202  return false;
203  }
204 
205  {
206  try
207  {
208  // this may seem funny, but we need to create an instance
209  // so shut down so that the package manager can unload
210  // the libraries (it needs to pass a RexxThreadContext
211  // pointer out to package unloaders, if they are defined)
212  InstanceBlock instance;
213  // run whatever uninits we can before we start releasing the libraries
214  memoryObject.verboseMessage("Calling runUninits through lastChanceUninit from Interpreter::terminateInterpreter\n");
216 
218  } catch (ActivityException)
219  {
220  // we're shutting down, so ignore any failures while processing this
221  }
222  }
223 
224  // perform system-specific cleanup
226 
227  // most interpreter resources will be cleanup automatically, but
228  // we need to poke the rxapi daemon and tell it to clean up our session
229  // resources.
231  }
232  return true;
233 }
234 
235 
236 /**
237  * Quick test if we're down to just a single interpreter instance.
238  *
239  * @return true if we're down to a single interpreter instance.
240  */
242 {
243  return interpreterInstances->items() == 1;
244 }
245 
246 
247 /**
248  * Create a new instance and return the instance context pointers
249  * and thread context pointer for the instance.
250  *
251  * @param instance The returned instance pointer.
252  * @param threadContext
253  * The returned thread context pointer.
254  * @param options Options to apply to this interpreter instance.
255  *
256  * @return 0 if the instance was created ok.
257  */
258 int Interpreter::createInstance(RexxInstance *&instance, RexxThreadContext *&threadContext, RexxOption *options)
259 {
260  try
261  {
262  // create the instance
263  InterpreterInstance *newInstance = createInterpreterInstance(options);
264  instance = newInstance->getInstanceContext();
265  threadContext = newInstance->getRootThreadContext();
266  // we need to ensure we release the kernel lock before returning
267  RexxActivity *activity = newInstance->getRootActivity();
268  activity->releaseAccess();
269  // the activity needs to be in a deactivated state when we return.
270  activity->deactivate();
271  return 0;
272  } catch (ActivityException)
273  {
274  // not everything works until an instance is actually created, so
275  // it's possible we'll see a true failure here, so give back an
276  // error condition.
277  return RXAPI_MEMFAIL;
278  }
279 }
280 
281 
282 /**
283  * Create a new interpreter instance. An interpreter instance
284  * is an accessible set of threads that constitutes an interpreter
285  * environment for the purposes API access.
286  *
287  * @param exits The set of exits to use for this invocation.
288  * @param defaultEnvironment
289  * The default addressible environment.
290  *
291  * @return The new interpreter instance.
292  */
294 {
295  // We need to ensure that the interpreter is initialized before we create an
296  // interpreter instance. There are some nasty recursion problems that can result,
297  // so this needs to be done carefully and the initialization needs to be protected by
298  // the resource lock during the entire process.
299  {
300  ResourceSection lock("Interpreter::createInterpreterInstance", 0);
301  // if our instances list has not been created yet, then the memory subsystem has not
302  // been created yet. Keep the lock during the entire process.
304  {
305  startInterpreter(RUN_MODE, NULL);
306  }
307  }
308 
309 
310  // get a new root activity for this instance. This might result in pushing a prior level down the
311  // stack
313  // ok, we have an active activity here, so now we can allocate a new instance and bootstrap everything.
314  InterpreterInstance *instance = new InterpreterInstance();
315 
316  {
317  ResourceSection lock("Interpreter::createInterpreterInstance", 0);
318 
319  // add this to the active list
320  interpreterInstances->append((RexxObject *)instance);
321  }
322 
323  // now that this is protected from garbage collection, go and initialize everything
324  instance->initialize(rootActivity, options);
325  return instance;
326 }
327 
328 
329 /**
330  * Shutdown an interpreter instance and remove it from the list
331  * of accessible items.
332  *
333  * @param instance The instance we're shutting down.
334  *
335  * @return true if this instance was in a state that could be terminated.
336  */
338 {
339  // instance has already shut itself down....we need to remove it from
340  // the active list.
341  ResourceSection lock("Interpreter::terminateInterpreterInstance", 0);
342 
344  return true;
345 }
346 
347 
348 /**
349  * Tell the interpreter to have all of the instances halt its activities.
350  */
352 {
353  ResourceSection lock("Interpreter::haltAllActivities", 0);
354  bool result = true;
355 
356  for (size_t listIndex = interpreterInstances->firstIndex() ;
357  listIndex != LIST_END;
358  listIndex = interpreterInstances->nextIndex(listIndex) )
359  {
360  /* Get the next message object to */
361  /*process */
363  // halt every thing
364  result = result && instance->haltAllActivities(name);
365  }
366  return result;
367 }
368 
369 
370 /**
371  * Manage a context where a new interpreter instance is created
372  * for the purposes of acquiring an activity, and the activity
373  * is released and the instance is terminated upon leaving the
374  * block.
375  */
377 {
378  // Get an instance. This also gives the root activity of the instance
379  // the kernel lock.
382 }
383 
384 
385 /**
386  * Manage a context where a new interpreter instance is created
387  * for the purposes of acquiring an activity, and the activity
388  * is released and the instance is terminated upon leaving the
389  * block.
390  */
392 {
393  // Get an instance. This also gives the root activity of the instance
394  // the kernel lock.
397 }
398 
399 
400 /**
401  * Manage a context where a new interpreter instance is created
402  * for the purposes of acquiring an activity, and the activity
403  * is released and the instance is terminated upon leaving the
404  * block.
405  */
407 {
408  size_t optionCount = 0;
409 
410  RexxOption options[3];
411 
412  // if we have exits specified, add this to the option set
413  if (exits != NULL)
414  {
415  options[optionCount].optionName = REGISTERED_EXITS;
416  options[optionCount].option = (void *)exits;
417  optionCount++;
418  }
419 
420  if (env != NULL)
421  {
422  options[optionCount].optionName = INITIAL_ADDRESS_ENVIRONMENT;
423  options[optionCount].option = (CSTRING)env;
424  optionCount++;
425  }
426 
427  // set the marker for the end of the options
428  options[optionCount].optionName = NULL;
429 
430  // Get an instance. This also gives the root activity of the instance
431  // the kernel lock.
434 }
435 
436 
437 /**
438  * Release the kernal access and cleanup when the context block
439  * goes out of scope.
440  */
442 {
444  // terminate the instance
445  instance->terminate();
446 }
447 
448 
449 /**
450  * Decode a condition directory into a easier to use
451  * structure form for a native code user. This breaks
452  * the directory into its component pieces, including
453  * converting values into primitive form using just a single
454  * API call.
455  *
456  * @param conditionObj
457  * A directory object containing the condition information.
458  * @param pRexxCondData
459  * The condition data structure that is populated with the
460  * condition information.
461  */
463 {
464  memset(condData, 0, sizeof(RexxCondition));
465  condData->code = messageNumber((RexxString *)conditionObj->at(OREF_CODE));
466  // just return the major part
467  condData->rc = messageNumber((RexxString *)conditionObj->at(OREF_RC))/1000;
468  condData->conditionName = (RexxStringObject)conditionObj->at(OREF_CONDITION);
469 
470  RexxObject *temp = conditionObj->at(OREF_NAME_MESSAGE);
471  if (temp != OREF_NULL)
472  {
473  condData->message = (RexxStringObject)temp;
474  }
475 
476  temp = conditionObj->at(OREF_ERRORTEXT);
477  if (temp != OREF_NULL)
478  {
479  condData->errortext = (RexxStringObject)temp;
480  }
481 
482  temp = conditionObj->at(OREF_DESCRIPTION);
483  if (temp != OREF_NULL)
484  {
485  condData->description = (RexxStringObject)temp;
486  }
487 
488  // this could be raised by a termination exit, so there might not be
489  // position information available
490  temp = conditionObj->at(OREF_POSITION);
491  if (temp != OREF_NULL)
492  {
493  condData->position = ((RexxInteger *)temp)->wholeNumber();
494  }
495  else
496  {
497  condData->position = 0;
498  }
499 
500  temp = conditionObj->at(OREF_PROGRAM);
501  if (temp != OREF_NULL)
502  {
503  condData->program = (RexxStringObject)temp;
504  }
505 
506  temp = conditionObj->at(OREF_ADDITIONAL);
507  if (temp != OREF_NULL)
508  {
509  condData->additional = (RexxArrayObject)temp;
510  }
511 }
512 
513 
514 /**
515  * Default class resolution processing done without benefit of
516  * a program context.
517  *
518  * @param className The class name.
519  *
520  * @return A resolved class object (if any).
521  */
523 {
524  RexxString *internalName = className->upper(); /* upper case it */
525  ProtectedObject p(internalName);
526  /* send message to .local */
527  RexxClass *classObject = (RexxClass *)(ActivityManager::getLocalEnvironment(internalName));
528  if (classObject != OREF_NULL)
529  {
530  return classObject;
531  }
532 
533  /* last chance, try the environment */
534  return(RexxClass *)(TheEnvironment->at(internalName));
535 }
536 
537 
538 /**
539  * Return the current queue name.
540  *
541  * @return The name of the current queue.
542  */
544 {
545  RexxObject *queue = ActivityManager::getLocalEnvironment(OREF_REXXQUEUE);
546 
547  if (queue == OREF_NULL) /* no queue? */
548  {
549  return OREF_SESSION; // the session queue is the default
550  }
551  // get the current name from the queue object.
552  return(RexxString *)queue->sendMessage(OREF_GET);
553 }
554 
555 
556 void Interpreter::logicError (const char *desc, const char *info1, size_t info2)
557 /******************************************************************************/
558 /* Function: Raise a fatal logic error */
559 /******************************************************************************/
560 {
561  if (info1) printf("Logic error: %s (%s %zi)\n",desc, info1, info2);
562  else printf("Logic error: %s\n",desc);
563  exit(RC_LOGIC_ERROR);
564 }
565 
567  RexxString *errorcode) /* REXX error code as string */
568 /******************************************************************************/
569 /* Function: Parse out the error code string into the messagecode valuey */
570 /******************************************************************************/
571 {
572  const char *decimalPoint; /* location of decimalPoint in errorcode*/
573  wholenumber_t primary = 0; /* Primary part of error code, major */
574  wholenumber_t secondary = 0; /* Secondary protion (minor code) */
575  size_t count;
576 
577  /* make sure we get errorcode as str */
578  errorcode = (RexxString *)errorcode->stringValue();
579  /* scan to decimal Point or end of */
580  /* error code. */
581  for (decimalPoint = errorcode->getStringData(), count = 0; *decimalPoint && *decimalPoint != '.'; decimalPoint++, count++);
582 
583  // must be a whole number in the correct range
584  if (!new_string(errorcode->getStringData(), count)->numberValue(primary) || primary < 1 || primary >= 100)
585  {
586  /* Nope raise an error. */
588 
589  }
590  // now shift over the decimal position.
591  primary *= 1000;
592 
593 
594  if (*decimalPoint)
595  { /* Was there a decimal point specified?*/
596  /* is the subcode invalid or too big?*/
597  if (!new_string(decimalPoint + 1, (errorcode->getLength() - count -1))->numberValue(secondary) || secondary < 0 || secondary >= 1000)
598  {
599  /* Yes, raise an error. */
601  }
602  }
603  return primary + secondary; /* add two portions together, return */
604 }
void reportException(wholenumber_t error)
#define LIST_END
Definition: ListClass.hpp:60
RexxList * new_list()
Definition: ListClass.hpp:147
ActivityException
#define OREF_NULL
Definition: RexxCore.h:61
#define TheEnvironment
Definition: RexxCore.h:183
#define env_find(s)
Definition: RexxCore.h:232
const int RC_LOGIC_ERROR
Definition: RexxCore.h:269
#define Error_Expression_result_raise
RexxReturnCode RexxEntry RexxCreateSessionQueue()
Definition: QueuesAPI.cpp:366
RexxReturnCode RexxEntry RexxDeleteSessionQueue()
Definition: QueuesAPI.cpp:353
RexxMemory memoryObject
Definition: RexxMemory.cpp:86
#define memory_mark(oref)
Definition: RexxMemory.hpp:450
#define memory_mark_general(oref)
Definition: RexxMemory.hpp:451
RexxString * new_string(const char *s, stringsize_t l)
static void createLocks()
static RexxObject * getLocalEnvironment(RexxString *name)
static void closeLocks()
static RexxActivity * getRootActivity()
RexxActivity * activity
InterpreterInstance * instance
static RexxObject * localServer
static bool lastInstance()
static void logicError(const char *desc, const char *info1=NULL, size_t info2=0)
static void live(size_t)
Definition: Interpreter.cpp:83
static bool timeSliceElapsed
static void decodeConditionData(RexxDirectory *conditionObj, RexxCondition *condData)
static void init()
Definition: Interpreter.cpp:77
static wholenumber_t messageNumber(RexxString *)
static void startInterpreter(InterpreterStartupMode mode, const char *imageTarget)
static void initLocal()
static bool terminateInterpreter()
static bool isActive()
Definition: Interpreter.hpp:92
static bool terminateInterpreterInstance(InterpreterInstance *instance)
static void createLocks()
Definition: Interpreter.hpp:78
static void closeLocks()
Definition: Interpreter.hpp:83
static RexxString * versionNumber
static RexxList * interpreterInstances
static void liveGeneral(int reason)
Definition: Interpreter.cpp:90
static RexxClass * findClass(RexxString *className)
static RexxString * getCurrentQueue()
static int createInstance(RexxInstance *&instance, RexxThreadContext *&threadContext, RexxOption *options)
static void processStartup()
static InterpreterInstance * createInterpreterInstance()
Definition: Interpreter.hpp:95
static bool haltAllActivities(RexxString *)
static void processShutdown()
static bool active
static SysMutex resourceLock
RexxInstance * getInstanceContext()
RexxActivity * getRootActivity()
bool haltAllActivities(RexxString *)
void initialize(RexxActivity *activity, RexxOption *options)
RexxThreadContext * getRootThreadContext()
static void unload()
void releaseAccess()
void exitCurrentThread()
RexxObject * at(RexxString *)
RexxObject * append(RexxObject *)
Definition: ListClass.cpp:538
size_t firstIndex()
Definition: ListClass.hpp:84
size_t nextIndex(size_t i)
Definition: ListClass.cpp:804
size_t items()
Definition: ListClass.hpp:97
RexxObject * removeItem(RexxObject *)
Definition: ListClass.cpp:1023
RexxObject * getValue(size_t i)
Definition: ListClass.cpp:276
void initialize(bool restoringImage, const char *imageTarget)
Definition: RexxMemory.cpp:179
static void createLocks()
bool savingImage()
Definition: RexxMemory.hpp:217
static void closeLocks()
void verboseMessage(const char *message)
Definition: RexxMemory.hpp:240
void lastChanceUninit()
Definition: RexxMemory.cpp:517
void sendMessage(RexxString *, RexxArray *, RexxDirectory *, ProtectedObject &)
bool messageSend(RexxString *, RexxObject **, size_t, size_t, ProtectedObject &, bool processUnknown=true, bool dynamicTarget=true)
RexxString * stringValue()
bool numberValue(wholenumber_t &result, size_t precision)
size_t getLength()
const char * getStringData()
RexxString * upper()
static void terminateInterpreter()
#define INITIAL_ADDRESS_ENVIRONMENT
Definition: oorexxapi.h:370
#define REGISTERED_EXITS
Definition: oorexxapi.h:381
const char * CSTRING
Definition: rexx.h:78
struct _RexxStringObject * RexxStringObject
Definition: rexx.h:128
struct _RexxArrayObject * RexxArrayObject
Definition: rexx.h:130
ssize_t wholenumber_t
Definition: rexx.h:230
#define RXAPI_MEMFAIL
Definition: rexxapidefs.h:61
wholenumber_t rc
Definition: oorexxapi.h:425
RexxStringObject description
Definition: oorexxapi.h:431
wholenumber_t code
Definition: oorexxapi.h:424
size_t position
Definition: oorexxapi.h:426
RexxArrayObject additional
Definition: oorexxapi.h:432
RexxStringObject conditionName
Definition: oorexxapi.h:427
RexxStringObject message
Definition: oorexxapi.h:428
RexxStringObject errortext
Definition: oorexxapi.h:429
RexxStringObject program
Definition: oorexxapi.h:430
ValueDescriptor option
Definition: oorexxapi.h:419
const char * optionName
Definition: oorexxapi.h:418