1. Introduction

Next chapter

GemBuilder™ for C is a library of C functions that provide access to the GemStone/S 64 Bit™ repository and the GemStone Smalltalk programming language from C applications, or from other environments that can invoke C functions.

The GemBuilder for C functions are provided by shared libraries that are distributed with the GemStone/S 64 Bit product. These shared libraries are used by the GemStone/S 64 Bit topaz interface, and by the GemBuilder for Smalltalk and GemBuilder for Java products. These libraries can be used from any environment that allows you to invoke C libraries, including Smalltalk implementations such as Dolphin and Pharo, and other languages such as Ruby and Python.

The GemStone object server contains your schema (class definitions) and objects (instances of those classes), while your GCI client program provides the user interface. Logic may be implemented on the client, server, or both; the GemBuilder functions allow your GCI application to create, read, and write objects in the GemStone repository either by invoking Smalltalk code or by using structural access and basic C data types.

The following interfaces allow your GemStone application to invoke C functions:

1.1  GemBuilder Application Overview

Figure 1.1 illustrates the role of GemBuilder in developing a GemStone application. In effect, developing your GCI application consists of two separate efforts: creating Smalltalk classes and methods, and interacting with C code.

Figure 1.1   The Role of GemBuilder in Application Development

We recommend the following steps for developing your hybrid application:

Step 1. Define the application’s external interface.

GemBuilder-based applications must manage the user interface using language-specific modules. GemStone and GemBuilder for C have no graphical user interface.

Step 2. Decide where to perform the work.

Applications that are a hybrid of client-side code and GemStone Smalltalk classes pose interesting problems to the designer: Where is the best place to perform the application’s work? Is it better to import the representation of an object into C data types and perform the work on the client, or to send a message which invokes a Smalltalk method on the server?

Step 3. Implement and debug the application.

After you’ve developed a satisfactory design, you can implement and test the client functions using language-specific techniques and tools.

Step 4. Compile and link the application.

For instructions about compiling and linking your application, please see Chapter 5, “Compiling and Linking” For full details, see your C compiler user documentation.

1.2  Deciding Where to Do the Work

As mentioned above, you will need to decide how much of the application’s work to perform in C functions on the client and how much in Smalltalk methods on the server. The following paragraphs discuss both approaches.

Representing GemStone Objects in C

You may choose to implement C functions that access GemStone objects for manipulation in your C program. In such cases, a representation of each object must be imported from GemStone into your C program before the C function is executed.

By import, we mean that memory is allocated within your C program to contain the C equivalent of the GemStone Smalltalk object. You could also say that these values are cached in your application; rather than having a reference to the object by identity (OOP), we have the contents of its instance variables. The object in its permanent form still exists in the repository, and the cached values in your application may become obsolete if other sessions commit changes to this object.

Exporting is the reverse of importing - you create a GemStone Smalltalk object that holds the equivalent to your C data, or update an existing GemStone Smalltalk object with the C data in your application.

GemBuilder provides functions for importing objects from GemStone to your C program, creating new GemStone objects, directly accessing and modifying the internal contents of objects, and exporting objects to the GemStone repository.

Of course, if you import an object to your C program and modify it, or if you create a new object within your C program, your application must export the new or modified object to GemStone before it can commit the changes to the repository.

Here are some advantages of using GemBuilder structural access functions to modify objects:

  • It may be more efficient to perform a function in C than in Smalltalk.
  • The function may need to be closely linked with I/O functions for the user interface.
  • The function may already exist in a standard library. In this case, the data must be transported from GemStone to that function.

The section Structural Access to Objects defines exactly how objects are represented in C as address space, and defines the GemBuilder functions for exchanging these structures between GemStone and C.

Smalltalk Access to Objects

In many cases, you will choose to perform your GemStone work directly in Smalltalk. GemBuilder provides C functions for defining and compiling Smalltalk methods for a class, and for sending a message to an object (invoking a Smalltalk method).

Here are some advantages of writing a function directly in Smalltalk:

  • The integrity of the data encapsulation provided by the object metaphor is preserved.
  • Functions in Smalltalk are more easily shared among multiple applications.
  • Functions in Smalltalk may be easier to implement. There is no need to worry about moving objects between C and Smalltalk or about space management.
  • The overhead of transporting objects between C and Smalltalk is avoided.
  • Classes or methods may already exist which exhibit behavior similar to the desired behavior. Thus, less effort will be required to implement a new function in Smalltalk.

The section Performing work in GemStone defines GemBuilder functions that allow applications to send Smalltalk messages to objects and execute Smalltalk code.

Environments

The GemStone server includes multiple execution environments, although normally Smalltalk applications exclusively use the primary environment, environment 0.

The GCI functions that support an environmentId argument include GciExecute* and GciPerform*, and non-blocking variants of these, that have names with a trailing underscore. These functions allow you to access other environments. These further environments were primarily intended to support Ruby applications, and are not described in this manual. Examine the header file $GEMSTONE/include/gci.hf for details.

1.3  Objects in GemStone and C data

An important feature of the GemStone data model is its ability to preserve an object’s identity distinct from its state. Within GemStone, each object is identified by a unique 64-bit object-oriented pointer, or OOP. Whenever your client application attempts to access or modify the state of a GemStone object, GemStone uses its OOP to identify it. Both the OOP and a representation of the object’s state may be imported into the client.

Your client application can only use predefined OOPs, or OOPs that it has received from the GemStone server; it cannot create new OOPs directly.

Since the client application accesses objects only via the OOP, the terms "OOP" and "Object" are used interchangeably in this manual, in function names, and in header comments. This differs from GemStone Smalltalk code and other GemTalk manuals, in which "OOP" is generally used to distinguish the numeric pointer value associated with an object from the object itself.

1.4  Garbage Collection

GemStone performs automatic garbage collection via several mechanisms, which are discussed more fully in the System Administration Guide for GemStone/S 64 Bit, in the chapter titled “Managing Growth”.

Garbage Collection includes

In-memory garbage collection

In-memory garbage collection occurs regularly in the Gem process, to ensure memory is available for ongoing needs. If newly created or temporary objects are not referenced, they run the risk of being garbage collected and disappearing prematurely during in-memory garbage collection. While you may have a reference the OOP of a temporary objects from data structures in your GCI application, this does not by itself prevent the actual object in the Gem process from being garbage collected. In-memory GarbageCollection can occur at any time, particularly if the GemStone session is in active use.

To avoid this problem, GemStone uses several internal sets in the Gem process, including the PureExportSet and the GciTrackedObjs set, that hold objects that need to be preserved from garbage collection. Before removing any objects, the GemStone in-memory garbage collector checks the PureExportSet and the GciTrackedObjs sets in the Gem’s workspace. Any object in these sets is considered to be referenced. User actions maintain their own export set, and objects in that set are also protected.

The garbage collector does not remove objects that are in these sets, and it also does not remove objects that are referenced by objects in these sets or by persistent object. Garbage Collection does not remove objects for which there is a reference path from an object that cannot itself be garbage collected.

When you execute a GemBuilder function that creates an object, the newly created object is automatically added to the PureExportSet, or in a user action, to the user action’s export set, to avoid any risk of it being garbage collected before it can be used.

Objects are automatically added to an export set in these cases:

  • The results of GciNew*, GciCreate*, GciSend*, GciPerform*, GciExecute* and GciResolve* calls are automatically added to the export set.
  • Objects returned in the report buffer of a GciFetchObjectInfo or GciClampedTrav, when GCI_RETRIEVE_EXPORT flag is set, will be added to the export set.
  • When the function GciErr(GciErrSType *errorReport) returns TRUE, values of type OopType in the *errorReport are added to the export set.

Objects that are the contents of instance variables, such as objects returned from a call to GciFetchOops, are not added to the export set. These are already referenced from the object with the instance variables. However, these objects are cached in your C code, and the values may no longer be valid if the referencing object becomes dirty due to an abort or commit.

GemBuilder does not automatically add other objects to the export sets. If you have temporary objects that should not disappear, the application must be careful to explicitly call GciSaveObjs or GciSaveGlobalObjs function when it needs to be sure to retain an object that is not already in an export set.

While code that is invoked from a GCI application automatically puts objects in the PureExportSet, code that is executed from within a user action has somewhat different requirements, and use the user action export set, rather than the PureExportSet, to preserve objects from garbage collection. When the user action comes to an end, the user action’s export set ceases to exist and the objects it contained may be garbage collected. This avoids the risk of objects not being released and holding on to memory; for example if the user action exits with an unexpected error. User actions can call GciSaveObjs to explicitly add objects to their export set, or GciSaveGlobalObjs to add specifically add them to the PureExportSet.

Tracked Objects

Another way to preserve objects from garbage collection is to add them to the tracked objects set. Use of this set requires calling GciTrackedObjsInit to initialize, and objects are explicitly added by passing them to GciSaveAndTrackOops.

Unreferenced persistent object garbage collection

In-memory garbage collection cleans up objects in session memory, and newly created objects or modified objects are put in the export set (or tracked objects set) to ensure that they are not garbage collected before the changes are committed.

When an existing persistent object (that is, an object that has references from other persistent objects, such as a collection) is no longer referenced, they also are subject to garbage collection. markForCollection and epoch garbage collection scan the repository and will dispose of persistent objects that have no reference chain from the repository root.

If the session commits changes that remove a persistent reference to an object, then that object may be at risk of persistent object garbage collection. If the session will be doing further work with that object, it should be added to the exported or tracked objects set, which protect objects from persistent as well as in-memory garbage collection.

Once a persistent object is disposed, its OOP may be reused for another objects. If a session did not add the object to the export set, in a busy application there is a chance that the next GemBuilder call specifying that object will either encounter an object does not exist error, or the object will be an entirely different one than expected.

Releasing Objects

Preserving objects from garbage collection is critical, however, these objects use memory and too many of them will impact performance.

Once the objects in the PureExportSet are no longer needed, the application can improve performance and avoid out of memory issues by calling one of the GciRelease... functions, to reduce the size of the set and permit garbage collection of obsolete temporaries.

Next chapter