Ingres CL MO
From Ingres Community Wiki
|
Ingres Compatability Library |
General Library Specification MO
Abstract
This is a proposed specification of an MO facility to be provided by the General Library for access to management objects.
Revision: 1.12, 24-Mar-1997
Document History
- Revision 0.1
- split from original MI and renamed MO for experimentation. This version is more explicitly object oriented, with name-instance treated separately.
- Revision 0.2
- add more permission concepts for five different roles, "System", "Security", "Installation", "DBA", and "Session".
- Revision 0.3
- remove MOscan; can't think of a real need and it was a complicated bag of worms. Remove CL_ERR_DESCs and other CL references.
- Revision 0.4
- remove memory stuff into separate GLalloc / GLfree / GLset_alloc; it's a common problem so solve it in a general way. Add MOstring, MOla, and MOlax; maybe some of these are bad ideas.
- ``I always speak Generally. -- Norman Schwartzkopf
- Revision 0.5,
- add thoughts about extending .0 access functions to eliminate the need to attach each instance, and contemplate ditching getnext_name.
- Revision 0.6
- make more object like; names are now classes, access functions are now "methods", and objects mean {class, instance}. Ditch next_name; can't figure out how to make it work reasonably in the face of methods. Would require a "GETNEXT_CLASS" message to be handled by the method, which seems practically very difficult. Each method would need to know what the "next" class was, and that would lose most of the value of the index in the tree.
- Revision 0.7
- add user permission; add pile of stuff for object-ids. Sigh.
- Revision 0.8
- clean up some object-id related stuff. Remove get_oid and get_name; they are redundant with get_meta. Add flags for field validity in meta data, allowing for garbage collection.
- Revision 0.9
- Remove "classid" args to methods and monitors. Neither can constructively use this information, particularly if handed a mapped object-id instead of the class the client used for the attachment. Add valid_perms as an argument to a number of functions to allow some enforcement by MO. Add session_context to get and get_next for use as a context by methods that may benefit having it for getnext. Remove get_meta, because you can just MOget the meta data.
- Revision 1.0
- Investigate things suggested in the first review. Clear up classes; allow only one caller of methods/monitors; collapse meta data to oid mapping, allow only char input to set, and char output from get/getnext. Make session_context a PTR *, so the method can store things there itself. Add method arg to attach, and add many arguments to the method. Attach can now define a class independent of an instance, and methods may be handed object addresses and sizes.
- Revision 1.1
- Following CL review of 31-Jan-92, make the following changes. (1) Split class definition and instance attachment; (2) delete single class/instance operations and do everything with tables of stuctures; (3) get rid of ATTACH and DETACH event messages; (4) separate "value" and "index" operations into separate methods; (5) eliminate use of flags to identify intrinsic methods. Supply them instead as functions; (6) Get rid of MOstring etc.from the public interface, and make that operation part of the definition/attachment; (7) various document organization and typo changes.
- Revision 1.2
- Following CL review of 7-Feb-92, (a) fixed typos and organization problems; (b) Remove mutex/unmutex--handle it internally; (c) remove discussion of gargage collection, hiding the issue.
- Revision 1.3
- Internal cleanup. Remove user permission.
- Revision 1.4
- Add methods/events for set/del monitor. Each needs to be handed the actual object type, and standard set/del method funcs are provided.
- Revision 1.5
- Remove hex/oct conversion flags, make the flags field now be an offset for use with structures, change get/set methods to use the offset. Remove defaulting of index method; user must specify MOidata_index instead of handing NULL. Allow VAR for class index and cdata. Allow defaulting index to classid, and cdata to classid or index. Provide MOcdata_index for one-stop object definition. Remove MO_INSTANCE_DEF structure and turn MOattach into a "one object" only interface taking arguments. Document MOstrout and MOlongout as public interfaces. Add MOivget. Remove dumb monitor methods.
- Revision 1.6,
- At request of BruceK, the first user of monitors, change set_method to allow multiple methods per-classid, and have both cookie and qual_regexp args.
- Revision 1.7
- Have tell_monitor and monitor functions take a value string as well. Monitor calls driven by MOget[next]/MOset give a real value, other internal calls pass NULL, and external calls pass whetever the client user wishes.
- Revision 1.8
- fix some gross typos.
- Revision 1.9
- More typos, clarifications etc. In particulat, getnext methods must return the first instance of the class if an empty instance is presented. Recover some function descriptions that got lost somehow (MOnoset, MOstrget, MOstrout, MOuintget, MOuintset, and MOuivget). Note that qual_regexp's don't work in this version.
- Revision 1.10
- Sigh, recover 1.9 by hand from postscript output as only the 1.7 source can be found. Add MOptrget and MOpvget methods, MOlstrout, and MOptrout. Note lack of ACLs.
- Revision 1.11, 30-Jul-94
- Last gasp corrections and updates.
- Revision: 1.12, 24-Mar-1997
- Translate to html format.
Specification
Introduction
The MO module provides ways of defining and working with management object. Clients export meter data and control knobs via a named class-instance space; other clients make this space visible to users via management protocol One such protocol is SQL, where the objects are presented as rows or columns in tables; another is the TCP/IP Simple Network Management Protocol (SNMP), and a third is the OSI Common Management Interface Protocol (CMIP). MO is intended to support all of these protocols, and a number of it's restrictions reflect those of these other interfaces.
Objects may be arbitrary program variables, accessed via client-supplied or standard "method" functions. Object may also be completely virtual, instantiated by user-provided method functions. Object classes provide permissions that may be used to enforce access control.
The following executable interfaces are provided:
| Table 1: MO functions | |
| Name | Description |
|---|---|
| Control | |
| MOon_off | enable/disable MO operations (for application clients). |
| Definition | |
| MOclassdef | define a class type. |
| MOdetach | detach an instance from the object space. |
| Query | |
| MOget | get data from the object. |
| MOgetnext | get next object in name, instance order. |
| MOset | set value for an instance. |
| Monitors | |
| MOset_monitor | set monitor function for a class. |
| MOtell_monitor | call any monitor functions set for a class. |
| Access Methods -- get | |
| MOintget | get integer at pointer |
| MOivget | get integer value |
| MOlstrget | get from string buffers, length bounded. |
| MOstrget | get from string buffers. |
| MOstrpget | get from pointers to string buffers. |
| MOptrget | get from pointer to pointer |
| MOpvget | get from pointer value. |
| MOuintget | get unsigned integer at pointer |
| MOuivget | get unsigned integer value |
| MOzeroget | get value of 0. |
| MOblankget | get all blanks. |
| Access Methods -- set | |
| MOintset | set integers |
| MOnoset | set nothing, error method for non-writable objects. |
| MOstrset | set string buffers. |
| MOuintset | set unsigned integers |
| Index Methods | |
| MOcdata_index | method to get cdata from class definition for one instance. |
| MOidata_index | method to get idata from attached instances. |
| MOname_index | method to get name from attached instances. |
| User Method Utilities | |
| MOlongout | convert and put a i4 with error checking. |
| MOptrout | convert and put a PTR with error checking. |
| MOstrout | put a string with error checking. |
| MOulongout | convert and put an unsigned longnat with error checking. |
A "Users guide to writing objects" is attached in Appendix A.
Library
GL
Intended Uses
MO is intended to provide an underlying mechanism for entity management under different management protocols. For instance, an SQL gateway might use the MOget, MOgetnext and MOset functions to objects made visible by the program. Similarly, the five Internet SNMP (RFC 1157) operations could map cleanly to MO if that were desired:
| Table 2: Mapping SNMP to MO | |
| SNMP | MO |
|---|---|
| GetRequest-PDU | MOget |
| GetRequestNext-PDU | MOgetnext |
| GetResponse-PDU | MOget[next] return |
| SetRequest-PDU | MOset |
| Trap-PDU | MOtell_monitor |
Concepts and Assumptions
Managed Objects
Managed objects are identified with a process-unique two-part key, consisting of a classid and an instance. There may be multiple instances of the same classid. Each object may have an associated value that is manipulated with a number of built in or client supplied methods. Objects are transient in MO; they have no persistence across the life of a process.
All objects within MO are scalars; there are no arrays or structure aggregate types (except the various character types). Arrays or aggregates are constructed out of scalars using the object naming conventions described below under Modeling.
Formal and experimental objects
Formal MIB objects are those that are documented for customer use, and which are also described/defined using the ASN.1 for operation with standard protocols. Objects in the formal MIB will be documented as part of various projects beyond the scope of MO proper. It is expected to be difficult to add things to the formal MIB, because of the support and documentation burden. All objects in the formal MIB will have object identifiers (oids), described below.
At this time, there are no objects in the formal MIB.
Because the formal MIB will be fairly rigid and inflexible, there is also an experimental MIB name space to be used for things that are not to be used by clients in portable product applications. These objects may be added with impunity, though it is wise to restrict them to a reasonably small number. The experimental MIB can be used for what has traditionally been done though tracepoints, NM symbols, and TRdisplay statements to the log output.
Object Naming Conventions
Within MO, there is one {classid, instance} object-space per process. The classid is actually a union of two disjoint sets used for class identification. The class or class name is the human sensible name, and is what all human originated queries will use as the key. The other method is the use of object ids, or oids. These are by products of the need to product standards amendable management objects defined with the ISO ASN.1 language. The syntax of each is shown below.
| Class | From the alphabet [a-zA-Z_\-\.], as in "ingres.server.serverPid". There may be class names that do not correspond to object ids. |
| Object-ID | From the alphabet [0-9\.], as in "1.3.6.1.4.1.3.3.3". Each object id corresponds to a single class name. The numbers in embedded object ids may not contain leading zeros. While `1.0.5' is a legal oid, `01.00.06' is not. |
| Instance | From the alphabet [a-zA-Z0-9_\-\.]. For objects that are within the formal MIB, instance values may not contain letters, only decimal digits and the decimal point. |
All are manipulated by MO as EOS-terminated non-multi-byte character strings.
Object-instances are occasionally described to humans with a composite key of the form
"classid.instance"
Note that classid and instance may both contain their own embedded "dot" separators, indicating hierarchies within each. In particular, instances are not numbers, they are strings. All the MO functions take classid and the instance as separate string arguments.
Modeling
having only one possible instance per-process are to be given the instance "0". For example, a scalar variable holding the number of connected users might be attached as
"exp.common.gcf.gca.connected_users.0"
(an array) is represented with multiple objects having the same classid , but having a different instance value for each logical row, acting as a row index. None of the rows may be the "0" instance. If the "0" instance exists as an accessible object, there should be no other instances of the class. "0" instance.
is represented using a different classid for each column, joined by identical instance values for each logical row. There must be an explicit index column for each table, which can be scanned for all the valid row instances.
Given a logical table that looks like this, with ``id as the index column:
| Table 3: Example abstract table | |||
| id | user | group | role |
|---|---|---|---|
| 1000 | me | wheel | admin |
| 2000 | him | users | user |
The typical MO representation would be as four classes, with the following instances (in MOgetnext order):
| Table 4: Example objects implementing an abstract table | ||
| Class | Instance | Value |
|---|---|---|
| group | 1000 | wheel |
| group | 2000 | users |
| id | 1000 | 1000 |
| id | 2000 | 2000 |
| role | 1000 | admin |
| role | 2000 | user |
| user | 1000 | me |
| user | 2000 | him |
Multiple-access paths
Actual objects may be multiply attached under different {classid, instance} combinations. This allows something to be attached once as an undocumented object, and again as a documented object. For instance, exp.cl.clf.tm.cpums.0 might be the CL internal representation, while server.cpums.0 might be a documented interface.
Twins - Mapping Class Names to Object IDs and back
As a particularly important case of multiple access paths, objects that are attached by name are also implicitly attached by their object id. Clients may examine the MO_META_CLASS_CLASS with an object id to see the "twin" name, and the MO_META_OID_CLASS with a name to see the twin object-id.
Actions on the class are reflected in the oid-twin, and vice-versa. That is, when a set is made on the class, a monitor for the oid-twin will be called; when the object is detached, the oid-twin goes away as well. Thus, the code providing objects needs only to be concerned with the class names, and never the OID values.
Object Ids may be assigned to named classed by setting the MO_META_OID_CLASS for the name to the string value of the object-id. When this is done, any existing attached objects for the class will be duplicated as if they had been attached by the oid as well.
Experimental Objects
Objects that are not defined for use in the formal MIB with ASN.1 should use the following convention for naming:
- exp.facility.subpart.whatever.instance
The use of "dot" separation of parts is preferred ton indicate hierarchical divisions, with underscore used within a subpart for readability, e.g.,
- exp.clf.cs.info.norm_prio.0
Permissions
Logical permissions are associated with each class, reflecting a number of different access roles: Session, DBA, Installation, System, and Security. MO relies on the client code to provide it with a mask of currently valid roles to use to enforce these permission bits. and enforces them as appropriate. If the client wants to do it's own enforcement, it may hand in a mask of all ones (~0), and look at the output permissions returned with the object.
Each class may have a permanent attribute, which indicates that objects in the class may not be detached by anyone.
If a class has neither read nor write permission specified, the object exists, but can't be seen on gets, and can't be written on sets. Write-only types are strongly discouraged.
There are permissions for current user, because MO does not provide for object ownership. All objects are owned by the process.
MO also does not presently aprovide permissions against individual users (ACLs) because doing so would add a great deal of overhead. (This may need revisiting in the future because of C2/B1 and SNMPv2).
The five roles are
a session may access the class; the data base administrator may access the class; the server or installation administrator** may access the class;
- Perhaps ingres or someone acting as ingres.
the system administrator** may access the class;
- Perhaps, root, backup, someone with SYSPRIV, or the SNMP agent.
perhaps the security officer in the "Orange Book" world may access the class; The definition of these roles is at the discretion of the calling code, in terms of the valperms masks it supplies to get and set calls.
Message Types
There are "message types" associated with methods and monitors, both discussed in sections below.
| Table 5: MO method/monitor message types | |
| Message | Means |
|---|---|
| MO_ATTACH | Instance being attached. |
| MO_DETACH | Instance being detached. |
| MO_GET | Retrieve value and permissions |
| MO_SET | Set value |
| MO_SET_MONITOR | Monitor being set for this class |
| MO_DEL_MONITOR | Monitor being deleted for this class |
Class Methods
Each class definition identifies method functions that are called when access to an instance is needed. These can be coded by the client defining the class, or you may use a number of pre-defined methods provided by MO for common operations. Provision for user-defined methods allows clients to do more complicated actions than simply reading or setting a variable.
There are three methods that must be provided in a class definition.
GET METHOD is handed an offset and an object size provided by the class definition, and a pointer provided by an index method, the length of an output buffer, and an output buffer. SET METHOD is handed the same arguments as a get method, in order identifying the inputs and outputs. It takes the input character buffer and makes the instance identitified by the object take that value. INDEX METHOD is given a message type (either MO_GET or MO_GETNEXT), a pointer of data associated with the class, the length of the instance buffer, an instance buffer, and the address of a pointer that will be filled in with instance-specific data. If the message is GET NEXT, then the instance will be modified to contain the instance returned. GET handles the direct mapping of instance to instance-data, and GET NEXT enforces the ordering of instances. Some reasons to use user-methods include:
Changing a limit might need shut down an existing configuration and restart it with the new value -- provide a special SET method. Making visible instances that can't be explicitly attached -- provide a special INDEX method. Providing different conversions from string to internal type (and back) than are provided by the internal methods -- provide special GET and SET methods. Two of the three provided index methods (MOidata_index and MOname_index) look up instances that have been explicitly attached. The other, MOcdata_index is for single instance classes whose objects are known at the time of class definition. A typical user index method walks through it's own tree or array to find objects by instance. Examples are presented in Appendix A.
There are a number of standard methods provided for use in client class definitions.
| Table 6: MO standard method functions | ||
| Name | Type | Description |
|---|---|---|
| Get methods for unreadable control objects | ||
| MOblankget | MO_GET_METHOD | Get a buffer full of blanks. |
| MOzeroget | MO_GET_METHOD | Get a buffer with string of value zero. |
| Set methods for unwritable monitor objects | ||
| MOnoset | MO_SET_METHOD | Set method for read-only classes. |
| Methods for integers | ||
| MOintget | MO_GET_METHOD | Get string of value at instance data. |
| MOivget | MO_GET_METHOD | Get string of integer of instance data |
| MOintset | MO_SET_METHOD | Set integer from input string. |
| Methods for unsigned integers | ||
| MOuintget | MO_GET_METHOD | Get string of unsigned value at instance data. |
| MOuivget | MO_GET_METHOD | Get string of unsigned integer of instance data |
| MOuintset | MO_SET_METHOD | Set unsigned integer from input string. |
| Methods for pointers | ||
| MOptrget | MO_GET_METHOD | Get string of pointer at instance data. |
| MOpvget | MO_GET_METHOD | Get string of pointer of instance data. |
| Methods for unsigned integers | ||
| MOptrget | MO_GET_METHOD | Get string of unsigned value at instance data. |
| Methods for strings | ||
| MOstrget | MO_GET_METHOD | Get string from string buffer. |
| MOstrpget | MO_GET_METHOD | Get string from pointer to string buffer. |
| MOstrset | MO_SET_METHOD | Set string buffer from string buffer. |
| Index Methods | ||
| MOidata_index | MO_INDEX_METHOD | Get idata from attached instance idata. |
| MOcdata_index | MO_INDEX_METHOD | Get idata from class definition cdata. |
| MOname_index | MO_INDEX_METHOD | Get name from attached instances. |
MO does not provide floating point methods, and their use is discouraged for compatibility with other management protocols. If you are dealing with an accumulator that may exceed the range of a longnat, consider scaling it. For instance, a variable keeping count of GC I/O volume might be scaled to Kbytes or Mbytes rather than being raw bytes. Perhaps you keep the counter as floating, but present it as scaled Kbytes.
The GETNEXT Problem for index methods
There are classes where it is inconvenient or impossible to explicitly attach each instance. In these cases, a method must be defined for the class, and it is called for all operations. This means that it must provide the appropriate ordering of instances for the GETNEXT operation. This can be difficult, because the instance may not known. For instance, the string of an control block address might be used as the instance, but there might not be an ordered list of control blocks visible to the method. The solutions to this problem are discussed in Appendix A.
Monitors
MO provides "monitor functions" to assist support of event driven programs, where things are called when something happens rather than polling to observe changes. Monitors are attached to classes by clients, and are distinct from method functions. Methods are owned by the person writing the object; Monitors are owned by clients that have no visibility on the objects.
The expectation is that there will be relatively few objects written requiring these calls, and that they be driven rarely. ``Relatively few means handfulls, and ``rarely means a total monitor rate of 1-10/second or so. It is not intended to handle hundreds or thousands or monitor calls per second for hundreds of classids.
Coordination of meanings between objects and monitor functions is defined by clients and object providers. MO merely coordinates the rendezvous though its object space.
Multiple monitors may be hung onto a classid with the MOset_monitor call. The monitors on a classid are distinguished by having unique "monitor data" , values, similar to the class data given to an class definition or the instance data provided with an MOattach. This might be the address of a control block for the monitor operation, especially if one monitor function is being used to watch many different classids.
When MOset, MOget or MOgetnext are called on that instance or class, the monitor functions for the class will be called. Monitors may also be explicitly driven by client code calling MOtell_monitor.
At present, monitors will be called for all instances of a classid; the qual_regexp is ignored. In the future, the instances will be filtered by considering the qual_regexp handed in when the monitor was set. If it was NULL, or if the actual instancematches theregulat expression, then the monitor would be called. This will be done when there is a regular expression module in the GL for MO to call.
A called monitor is provided the classid, the classid of it's twin, (if one exists), the instance, a value and a message. If the message is MO_GET or MO_SET, and the call was made implicitly by MO, then the value is the current value of the object. Other internal calls pass a NULL value. Explicit calls to MOtell_monitor deliver whatever value the client wishes to send.
Changes to objects are only signaled to monitors if (a) the the change was made by an MOset operation, or (b) the code that made the change explicitly calls MOtell_monitor that something happened. Many objects are written with get methods like MOintget, which report the value of an existing variable when queried. Changes to these variables will not drive monitors without the explicit MOtell_monitor calls.
Memory Allocation
Some MO routines allocate and release memory by calling MEreqmem and MEfree. These are documented in the function descriptions. There are limits defined for the amount of memory that may be allocated by MO, and within that limit, how much may be used for string space. These may be manipulated with the MO_MEM_LIMIT and MO_STR_LIMIT classes, described below.
String space is used to cache non-constant strings that are provided as classids, indexes, and instances in calls to MOclassdef and MOattach. Strings that become unreferenced through calls to MOdetach are released.
Ordering
MO provides efficient ordered keyed access to items addressed by "{classid, instance}" with MOgetnext calls. The ordering is compatible with STcompare over the limited alphabet described in in "Object Naming Conventions" .
This may cause a problem matching database ordering for joins. STcompare is not the fancy ADF database comparison functions, which is not visible to the General Library. Use of ADF stuff would preclude use of MO by CL code, and enlarge otherwise small executables. The current GWF code is incapable of dealing with ordering from the GW that is different from that of the database. Thus, MO data made visible in a database with non-STcompare ordering may result in improper joins.
Initialization
MO is self-initializing. Calls can be made in any order, and must always produce the expected results. This is because we can't predict when something will start attaching things, and it might be before it is possible to explicitly initialize MO.
Re-entrancy
The MO routines are re-entrant, but the underlying object space is not. MO protects it's object space by acquiring MU_SEMAPHOREs at appropriate places to ensure consistency.
Persistence
The strings provided as classes and instances to attach calls must remain valid until they can no longer be accessed unless the appropriate VAR flags are handed in to cause them to be saved by MO. Strings provided as compile time constants are constant and don't need to be stashed. Strings built into local buffers are volatile, and do need to be saved.
The MOget routines alway fill an output buffer with a copy of the value, so there is no obligation on the caller to maintain validity after a detach.
Self Management
MO defines a number of internal classes. One set provides statistics on call counts to MO. Another set is for control of the string cache and memory allocation. The last is for accessing the meta data contained in classid descriptions. The only meta-data instances that must be defined are those identifying twin class/object-id pairs; others are optional.
The following classes provide counts of calls to external routines.
| Table 7: MO Call counters | |
| Class | Description |
|---|---|
| public interfaces | |
| MO_NUM_ATTACH | Calls to MOattach |
| MO_NUM_CLASSDEF | Calls to MOclassdef |
| MO_NUM_DETACH | Calls to MOdetach |
| MO_NUM_GET | Calls to MOget |
| MO_NUM_GETNEXT | Calls to MOgetnext |
| MO_NUM_DEL_MONITOR | For client use |
| MO_NUM_SET_MONITOR | For client use |
| Internal interfaces | |
| MO_NUM_ALLOC | Calls to allocate memory. |
| MO_NUM_FREE | Calls to free memory. |
The following self-management classes are provided
| Table 8: MO Meters | |
| Class | Description |
|---|---|
| MO_MEM_LIMIT | Max memory that MO may allocate |
| MO_MEM_BYTES | Current amount of memory MO has allocated. |
| MO_MEM_FAIL | Allocator calls that hit the limit. |
| MO_STR_LIMIT | Max memory that may be used by strings. |
| MO_STR_BYTES | Current memory used for strings. |
| MO_STR_FREED | Bytes recovered by garbage collection. |
| MO_STR_FAIL | String saves that hit the limit. |
The strings classes are indexed by the string values.
| TabTable 9: MO String table classes | |
| Class | Description |
|---|---|
| MO_STRING_CLASS | String value in the cache. |
| MO_STRING_REF_CLASS | References to the string. |
Meta Data
A number of classes are provided for access to the meta data contained in the class definitions. The live meta data is stored in the MO space indexed by classid in these classes. Some ancilliary classes are defined for use by clients, but are not maintained by MO. All of these classes are indexec by MO_META_CLASSID_CLASS.
| Table 10: MO Meta Data Classes | |
| Class | Description |
|---|---|
| Always present | |
| MO_META_CLASSID_CLASS | The classid as defined. |
| MO_META_OID_CLASS | The twin OID of the classid. |
| MO_META_CLASS_CLASS | The twin class name of the classid. |
| MO_META_SIZE_CLASS | The size of the objects in the class. |
| MO_META_PERMS_CLASS | The permissions for objects in the class. |
| MO_META_INDEX_CLASS | The index classes for objects in the class. |
| Possibly present | |
| MO_META_SYNTAX_CLASS | The SNMP syntax for the class. |
| MO_META_ACCESS_CLASS | The SNMP access for the class. |
| MO_META_DESC_CLASS | The description for the class. |
| MO_META_REF_CLASS | The SNMP reference for the class. |
The index is the name of the classid providing an index column for the table.
Header file <mo.h>
Manifest Constants
Error codes
The following error codes are defined and may be checked by calling code as specified for the individual functions.
MO_ALREADY_ATTACHED Attempt to re-attach an existing instance. This is a programming error. MO_BAD_MSG An index method or a monitor function got a msg that it didn't expect. This is a programming error. MO_BAD_SIZE A get or set method was given an object size that didn't expect. This is a programming error. MO_CLASSID_TRUNCATED The classid buffer handed to an index method wasn't large enough, and the return value was truncated to fit. This is a programming error. MO_INCONSISTENT_CLASS A classid was being defined a second time, and the new definition wasn't the same as the first one. This is a programming error. MO_INSTANCE_TRUNCATED The instance buffer handed to an index method wasn't large enough, and the return value was truncated to fit. This is a programming error. MO_NO_CLASSID The classid specified isn't defined. MO_NO_DETACH Attempt to detach an instance of a class that had the MO_PERMANENT flag set. This is a programming error. MO_NO_INSTANCE The instance requested doesn't exist, or permissions to read the class don't exist. MO_NO_NEXT There is no successor to the requested instance. MO_NO_READ You don't have permissions to get instances of the classid. MO_NO_STRING_SPACE A class definition or instance attach would use up too much string space memory. MO_NO_WRITE You don't have permissions to set instances of the classid. MO_NULL_METHOD The class definition did not provide necessary get or set methods. This is a programming error. MO_VALUE_TRUNCATED The instance buffer handed to an index method wasn't large enough, and the return value was truncated to fit. This is a programming error. MO_MEM_LIMIT_EXCEEDED An internal allocation request would have caused MO to exceed it's allocated memory limit
Wired in classes
These classes may be used to store meta data. Clients should use the defined symbol whenever possible.
- define MO_NUM_ATTACH "exp.gl.glf.mo.num.attach"
- define MO_NUM_CLASSDEF "exp.gl.glf.mo.num.classdef"
- define MO_NUM_DETACH "exp.gl.glf.mo.num.detach"
- define MO_NUM_GET "exp.gl.glf.mo.num.get"
- define MO_NUM_GETNEXT "exp.gl.glf.mo.num.getnext"
- define MO_NUM_SET_MONITOR "exp.gl.glf.mo.num.set_monitor"
- define MO_NUM_TELL_MONITOR "exp.gl.glf.mo.num.tell_monitor"
- define MO_NUM_MUTEX "exp.gl.mo.num.mutex"
- define MO_NUM_UNMUTEX "exp.gl.mo.num.unmutex"
- define MO_NUM_ALLOC "exp.gl.glf.mo.num.alloc"
- define MO_NUM_FREE "exp.gl.glf.mo.num.free"
- define MO_MEM_LIMIT "exp.gl.glf.mo.mem.limit"
- define MO_MEM_BYTES "exp.gl.glf.mo.mem.bytes"
- define MO_STR_LIMIT "exp.gl.glf.mo.strings.limit"
- define MO_STR_BYTES "exp.gl.glf.mo.strings.bytes"
- define MO_STR_FREED "exp.gl.glf.mo.strings.freed"
- define MO_STRING_CLASS "exp.gl.glf.mo.strings.vals"
- define MO_STRING_REF_CLASS "exp.gl.glf.mo.strings.refs"
- define MO_META_CLASSID_CLASS "exp.gl.glf.mo.meta.classid"
- define MO_META_OID_CLASS "exp.gl.glf.mo.meta.oid"
- define MO_META_CLASS_CLASS "exp.gl.glf.mo.meta.class"
- define MO_META_SIZE_CLASS "exp.gl.glf.mo.meta.size"
- define MO_META_PERMS_CLASS "exp.gl.glf.mo.meta.perms"
- define MO_META_INDEX_CLASS "exp.gl.glf.mo.meta.index"
- define MO_META_SYNTAX_CLASS "exp.gl.glf.mo.meta.syntax"
- define MO_META_ACCESS_CLASS "exp.gl.glf.mo.meta.access"
- define MO_META_DESC_CLASS "exp.gl.glf.mo.meta.desc"
- define MO_META_REF_CLASS "exp.gl.glf.mo.meta.ref"
Operations for MOon_off(), and returned as state
These codes are passed as operations to MOon_off, and it returns MO_ENABLE or MO_DISABLE as the old state.
- define MO_ENABLE 1
- define MO_DISABLE 2
- define MO_INQUIRE 4
Permissions
These define access permissions for classes. They are used in calls to MOclassdef, and are returned in calls to MOget and MOgetnext.
The defined permissions are:
MO_PERM_NONE no permission to read or write. MO_SES_READ instance may be read by the session. MO_SES_WRITE instance may be written by the session. MO_DBA_READ instance may be read by the dba. MO_DBA_WRITE instance may be written by the dba. MO_SERVER_READ instance may be read by the server administrator. MO_SERVER_WRITE instance may be written by the server administrator. MO_SYSTEM_READ instance may be read by the system administrator. MO_SYSTEM_WRITE instance may be written by the system administrator. MO_SECURITY_READ instance may be read by the security officer. MO_SECURITY_WRITE instance may be written by the security officer. Permissions may be modified with the following flag:
MO_PERMANENT may not be detached by anyone. The actual definitions are:
- define MO_SES_READ 00000002
- define MO_SES_WRITE 00000004
- define MO_DBA_READ 00000020
- define MO_DBA_WRITE 00000040
- define MO_SERVER_READ 00000200
- define MO_SERVER_WRITE 00000400
- define MO_SYSTEM_READ 00002000
- define MO_SYSTEM_WRITE 00004000
- define MO_SECURITY_READ 00020000
- define MO_SECURITY_WRITE 00040000
- define MO_PERMS_MASK 00066666
/* all may read, or mask for someone may read */
- define MO_READ ( MO_SES_READ | \
MO_DBA_READ | MO_SERVER_READ | \
MO_SYSTEM_READ | MO_SECURITY_READ )
/* all may write, or mask for someone may write */
- define MO_WRITE ( MO_SES_WRITE | \
MO_DBA_WRITE | MO_SERVER_WRITE | \
MO_SYSTEM_WRITE | MO_SECURITY_WRITE )
- define MO_PERMANENT 01000000
Message Types
Method functions and monitors are sent the the following message types indicating the event to be handled.
MO_GET The instance is being queried for its value. MO_GETNEXT This instance is being queried for the value of the next instance. MO_SET The instance is being set to a new value. MO_SET_MONITOR The class is getting a new monitor; used by clients only, never used internally. MO_DEL_MONITOR The class is deleting a monitor; used by clients only, never used internally.
String persistance flags
The following values may be or-ed together in the flags fields of the MO_CLASS_DEF and MO_INSTANCE_DEF structures discussed below. If one is set, it means the matching string needs to be saved in the string cache because the caller knows it is unstable.
MO_CLASSID_VAR the classid string must be saved, because what is here is transient. MO_INDEX_VAR the index string must be saved, because what is here is transient. MO_CDATA_VAR the cdata is a string and must be saved, because what is here is transient. MO_INSTANCE_VAR the instance string must be saved, because what is here is transient. MO_INDEX_CLASSID Use the classid as the index, and ignore MO_INDEX_VAR. MO_CDATA_CLASSID Use the classid as the cdata, and ignore MO_CDATA_VAR. MO_CDATA_INDEX Use the index as the cdata, and ignore MO_CDATA_VAR.
Function Types
MO_GET_METHOD Function type
typedef STATUS MO_GET_METHOD( nat offset,
nat objsize,
PTR object,
nat luserbuf,
char *userbuf );
MO_SET_METHOD Function Type
typedef STATUS MO_SET_METHOD( nat offset,
nat luserbuf,
char *userbuf,
nat objsize,
PTR object );
MO_INDEX_METHOD Function Type
/* Msg is either MO_GET or MO_GETNEXT */
typedef STATUS MO_INDEX_METHOD( nat msg,
PTR cdata,
nat linstance,
char *instance,
PTR *instdata );
MO_MONITOR_FUNC Function Type
A monitor function as expected by MOset_monitor and called directly by MOtell_monitor, or indirectly by other functions.
typedef STATUS MO_MONITOR_FUNC( char *classid,
char *twinid,
char *instance,
char *value,
nat msg,
PTR mon_data );
Data Structures
MO_CLASS_DEF structure This is an element in a table passed to MOclassdef
If the idx method is either MOidata_index or MOname_index, the cdata must be the name of a classid; this may either be the classid (by specifying MO_CDATA_CLASSID) or the index (by specifying MO_CDATA_INDEX).
typedef struct {
nat flags; /* MO_CLASSID_VAR | MO_INDEX_VAR |
MO_INDEX_CLASSID | MO_CDATA_CLASSID |
MO_CDATA_INDEX */
char *classid; /* name of the class */
nat size; /* size of object */
nat perms; /* permissions on all instances */
char *index; /* classids forming the index,
comma separated */
nat offset; /* value given to get/set methods */
MO_GET_METHOD *get; /* get conversion */
MO_SET_METHOD *set; /* set conversion */
PTR cdata; /* global data for classid, passed
to index methods */
MO_INDEX_METHOD *idx; /* for get/getnext. */
} MO_CLASS_DEF;
MO_INSTANCE_DEF structure This is an element in a table handed to MOattach or MOdetach. MOdetach only looks at the classid and instance fields.
typedef struct {
nat flags; /* MO_INSTANCE_VAR or 0 */ char *classid; /* the classid name */ char *instance; /* the instance string */ PTR idata; /* the data for the instance */
} MO_INSTANCE_DEF;
MACROS
MO_SIZEOF_MEMBER - compile time size of a structure member MO_SIZEOF_MACRO is a macro which yields the size in bytes of a member within its structure in a way that is suitable for use in initializing static variables at compile time.
MO_SIZEOF_MACRO is similar in feel to the CL_OFFSETOF the macro, and used for similar purposes.
Inputs: s_type the name of a structure type m_name the name of a member of the structure Outputs: None Returns: The size in bytes of member m_name in the structure s_type.
Definition: u_nat MO_SIZEOF_MACRO(s_type, m_name)
Example: MO_CLASS_DEF My_classes[] = {
{
0,
"exp.back.myfacility.my_struct.field_one",
MO_SIZEOF_MEMBER( MY_STRUCT, field_one ),
MO_READ,
0,
CL_OFFSETOF( MY_STRUCT, field_one ),
MOintget,
MOnoset,
(PTR)&My_struct,
MOcdata_index
},
{ 0 }
};
Implementation Notes:
While the ``zero-points-to trick is appealing:
- define MO_SIZEOF_MEMBER(struct, member) (sizeof((struct *)0)->member)
It does not compile everywhere. Instead, it's better to define a dummy object and use it instead: GLOBALREF ALIGN_RESTRICT MO_sizeof_trick;
- define MO_SIZEOF_MEMBER(s_type, m_name) \
(sizeof( ((s_type *)&MO_sizeof_trick)->m_name) )
Executable Interface
MOattach - attach instances If MOon_off has been called with MO_DISABLE, returns OK without doing anything.
Attachs an instance of a classid. If a classid has a corresponding object-id (as determined by looking up the classid in the MO_META_OBJID class), it is attached under the oid as well.
If the flags field contains MO_INSTANCE_VAR, then the instance string will be saved in allocated space, otherwise only a pointer will be kept. The idata may be passed by the MOidata_index method to the get and set methods for the class. This pointer will usually identify the actual object in question.
Allocates memory for the object using MEreqmem.
If the call succeeds, it must also call the monitors for the class with the MO_ATTACH event, the instance id, and a NULL value.
Inputs: flags either 0 or MO_INSTANCE_VAR if the instance string is not in stable storage. classid the classid of this class. instance being attached. idata the value to associate with the instance, picked out by the MOidata_index method and handed to get and set methods. Returns: OK is the object was attached successfully. MO_NO_CLASSID if the classid is not defined. MO_ALREADY_ATTACHED the object has already been attached. MO_NO_MEMORY if the MO_MEM_LIMIT would be exceeded. MO_NO_STRING_SPACE if the MO_STR_LIMIT would be exceeded. other error statuses, possibly indicating allocation failure of some sort. Prototype: STATUS MOattach( nat flags, char *classid, char *instance, PTR idata );
MOblankget - get integer buffer of blanks method This get method is for use with writable control objects. It fills in the output buffer with a string of blanks. The offset, object, and size are ignored.
Inputs: offset ignored. objsize ignored. object ignored. luserbuf the length of the user buffer. userbuf the buffer to use for output. Outputs: userbuf Filled with blanks. Returns: OK if the operation succeseded Prototype: STATUS MOblankget( nat offset,
nat objsize,
PTR object,
nat luserbuf,
char *userbuf )
MOcdata_index - standard index method for single instance class Index for using the cdata of the class definition as the data belonging to instance "0" of the class. MO_GETNEXT never succeeds.
If the instance is not the string "0" , returns MO_NO_INSTANCE. If the msg is MO_GET, uses the input cdata value as the output instdata. If msg is MO_GETNEXT, returns MO_NO_NEXT.
Inputs: msg either MO_GET or MO_GETNEXT cdata class specific data that will be used as the output instdata for instance "0" on an MO_GET. linstance the length of the instance buffer instance the instance in question. instdata a pointer to a place to put instance-specific data. Outputs: instdata filled in with appropriate idata for the attached instance. Returns: OK if the operation succeeded. MO_NO_INSTANCE if the requested instance does not exist. MO_NO_NEXT if there is no instance following the specified one in the class. Prototype: MO_INDEX_METHOD MOcdata_index;
STATUS MOcdata_index(nat msg,
PTR cdata,
nat linstance,
char *instance,
PTR *instdata );
MOclassdef - define a class If MOon_off has been called with MO_DISABLE, returns OK without doing anything.
Interprets up to nelem elements in the classes array as definitions of classes. The array may be terminated by a member having a NULL classid value.
For each class, if the flags contain MO_CLASSID_VAR or MO_INDEX_VAR, then the string will be saved in allocated space, otherwise only a pointer will be kept. The object size is subsequently passed along to get and set methods, and is the same for all instances. The perms field will be AND-ed with valid permissions given to the MOget and MOset functions to provide some security. The offset field will be passed uninterpreted to the get and set methods for their use. The get band set fields define the functions that will be used to convert back and forth between internal representations and character form. The cdata field contains data that will be passed uninterpreted to the idx index method. The cdata allows the index method to know what class it is being used for. In particular, the MO provided MOname_index and MOidata_index methods require that this be the name of a classid. This is usually either the actual classid, by specifying MO_CDATA_CLASSID, or the index class, by specifying MO_CDATA_INDEX.
Returns OK if the class was defined sucessfully. If the class is already defined, MOattach will return OK if the current definition is the same as the old one. If it is not, returns MO_INCONSISTENT_CLASS, and the original definition remains unaffected.
Allocates memory for definition using MEreqmem.
Inputs: nelem the maximum number of elements in the table to define classes A pointer to an array of class definitions, terminated with one having a null classid field. Outputs: none Returns: OK is the object was attached successfully. MO_INCONSISTENT_CLASS the object has already been attached. MO_NO_MEMORY if the MO_MEM_LIMIT would be exceeded. MO_NO_STRING_SPACE if the MO_STR_LIMIT would be exceeded. MO_NULL_METHOD A null get or set method was provided, but the permissions said get or set was allowed. other system specific error status, possibly indicating allocation failure. Prototype: STATUS MOclassdef( nat nelem, MO_CLASS_DEF *classes );
Example:
MOdetach - detach an attached instance Detaches an attached instance. Subsequent attempts to get or set it will fail, and an attempts to attach it will succeed.
Frees memory allocated by MOattach using MEfree.
If the call succeeds, it must also call the monitors for the class with the MO_DETACH event, the instance id, and a NULL value.
Inputs: classid the classid of the object. instance the instance of the object. Outputs: none Returns: OK if the classid was detached. MO_NO_INSTANCE if classid is not attached. MO_NO_DETACH if the object was attached as MO_PERMANENT. Prototype: STATUS MOdetach( char *classid, char *instance );
MOget - get data associated with an instance. Return the string value of the the requested instance. Returns MO_NO_INSTANCE if the object doesn't exist. If the object exists but is not readable, returns MO_NO_READ.
Existance of the object is determined by calling the index method for the class with the MO_GET method. If this returns OK, then the instance value it provided is passed to the get method for the class, which fills in the buffer supplied to MOget.
If the call succeeds, it must also call the monitor for the class with the MO_GET event, the instance id, and the current value.
Inputs: valid_perms the roles currently in effect, to be and-ed with object permissions to determine access rights. classid the classid in question. instance the instance in question. lsbufp pointer to length of the string buffer handed in, to be used for output if needed. Outputs: lsbufp filled in with the length of the string written to sbuf. sbuf contains the retrieved string value. perms the permissions for the classid. Returns: OK if the retrieval returned data. MO_NO_INSTANCE if class is not attached, or if the object permissions are non-zero but do not include the valid_perms bits. MO_NO_READ if a user with valid_perms isn't allowed to read it. MO_VALUE_TRUNCATED if the value wouldn't fit in the provided sbuf. "other error status" returned by a method. Prototype: STATUS MOget( nat valid_perms,
char *classid,
char *instance,
nat *lsbufp,
char *sbuf;
nat *perms );
Example:
MOgetnext - get next object in class, instance order. Given an object, attempts to return the next one that is readable. Ordering is as by STcompare of { classid, instance } of objects including the input valid_perms bits.
As important special cases, if the classid and instance are both a 0 length strings, then return the first of any instances in the class space that match its valid_perms. If only the instance is a 0 length string, then the return is the first instance of that or a subseqent class.
If the input instance does not exist or doesn't include valid_perms, returns MO_NO_INSTANCE, and the output class is untouched. If there is no readable successor to the input object, returns MO_NO_NEXT.
If the classid of the returned object won't fit in the provided buffer, returns MO_CLASSID_TRUNCATED. If the instance of the returned object won't fit in the provided buffer, returns MO_INSTANCE_TRUNCATED. If the value returned won't fit in the supplied buffer, returns MO_VALUE_TRUNCATED. Any of these truncation errors is a serious programming error, which should abort processing as it may be impossible to continue a get next scan from that point. Client buffers should always be sized big enough to avoid truncation, so truncation is a serious programming error. MOgetnext will not work as desired when handed a truncated classid or instance for a subsequent call.
Existance of the input object is determined by calling the idx method for the class with the MO_GETNEXT message.
If the call succeeds, it must also call the monitors for the class with the MO_GET event, the instance id, and the current value.
Inputs: valid_perms the roles currently in effect, to be and-ed with object permissions to determine access rights. lclassid length of the buffer for the classid. classid the classid in question. linstance length of the buffer for the instance. instance the instance in question. lsbufp pointer to the length of the output string buffer. Outputs: classid filled in with the new classid. instance filled in with the new instance. lsbufp if *sval is NULL, contains the actual length of the value in sbuf. sbuf if sval is NULL, a copy of the output string. If it wasn't long enough, returns MO_TRUNCATED. perms the permissions for the returned instance. Returns: OK if the retrieval returned data. MO_CLASSID_TRUNCATED buffer for classod was too small, and output was truncated. MO_INSTANCE_TRUNCATED buffer for instance was too small and output was truncated. MO_VALUE_TRUNCATED buffer for value was too small, and output was truncated. MO_NO_INSTANCE the input class/instance did not exist, or it's permissions didnot include readable valid_perms bits MO_NO_NEXT ther was no readable object following the input one. other error status, returned by a method. Prototype: STATUS MOgetnext(nat valid_perms,
nat lclassid,
nat linstance,
char *classid,
char *instance,
nat *lsbufp,
char *sbuf;
nat *perms );
Example:
MOidata_index - standard index method for data of attached objects Index for instance data belonging to objects known through MOattach calls, for handing the user object pointer to the get/set/method. This is the normally used index method cdata of a classid, where there is only one instance of the class, known at the time of class definition.
The input cdata is assumed to be a pointer to a string holding the classid in question, usually by defining the class with MO_CDATA_CLASSID or MO_CDATA_INDEX. If msg is MO_GET, determine whether the requested instance exists. If it does, fill in instdata with the idata pointer provided in the attach call for use by a get or set method, and return OK. If the requested instance does not exist, return MO_NO_INSTANCE.
If the msg is MO_GETNEXT, see if the requested instance exists; if not return MO_NO_INSTANCE. Then locate the next instance in the class. If there is no successor instance in the class, return MO_NO_NEXT. If there is a sucessor, replace the input instance with the one found. Fill in instdata with the idata supplied when the instance was attached, for use by the get/set methods defined for the class. If the new instance won't fit in the given buffer (as determined by linstance ), return MO_INSTANCE_TRUNCATED, otherwise return OK.
Inputs: msg either MO_GET or MO_GETNEXT cdata class specific data from the class definition, assumed to be a pointer to the classid string. linstance the length of the instance buffer instance the instance in question. instdata a pointer to a place to put instance-specific data. Outputs: instdata filled in with appropriate idata for the attached instance. Returns: OK if the operation succeeded. MO_NO_INSTANCE if the requested instance does not exist. MO_NO_NEXT if there is no instance following the specified one in the class. MO_INSTANCE_TRUNCATED if the output instance of a GET_NEXT would not fit in the provided buffer. Prototype: MO_INDEX_METHOD MOidata_index;
STATUS MOidata_index(nat msg,
PTR cdata,
nat linstance,
char *instance,
PTR *instdata );
MOintget - standard get integer at an address method Convert the signed integer at the object location to a character string. This is often the wrong thing to use, as negative numbers are rare. The offset is treated as a byte offset to the input object . They are added together to get the object location.
The output userbuf , has a maximum length of luserbuf that will not be exceeded. If the output is bigger than the buffer, it will be chopped off and MO_VALUE_TRUNCATED returned.
The objsize comes from the class definition, and is the length of the integer, one of sizeof(i1), sizeof(i2), or sizeof(longnat).
Inputs: offset value from the class definition, taken as byte offset to the object pointer where the data is located. objsize the size of the integer, from the class definition. object a pointer to the integer to convert. luserbuf the length of the user buffer. userbuf the buffer to use for output. Outputs: userbuf contains the string of the value of the instance. Returns: OK if the operation succeseded MO_VALUE_TRUNCATED the output buffer was too small, and the string was truncated. other conversion-specific failure status as appropriate. Prototype: STATUS MOintget( nat offset,
nat objsize,
PTR object,
nat luserbuf,
char *userbuf )
MOintset - standard set integer method Convert a caller's string to an signed integer for the instance. This is often the wrong thing to use, as there aren't many things that can happily take negative values.
The offset is treated as a byte offset to the input object . They are added together to get the object location.
The input objsize is the size of the output integer, as in sizeof(i1), sizeof(i2), or sizeof(i4). The object location is taken to be the address of the integer. The userbuf contains the string to convert, and luserbuf. is ignored.
Inputs: offset value from the class definition, taken as byte offset to the object pointer where the data is located. luserbuf the length of the user buffer, ignored. userbuf the user string to convert. objsize the size of the integer, from the class definition. object a pointer to the integer. Outputs: object Modified by the method. Returns: OK if the operation succeseded MO_BAD_SIZE if the object size isn't something that can be handled. other conversion-specific failure status as appropriate. Prototype MO_SET_METHOD MOintset;
STATUS MOintset( nat offset,
nat luserbuf,
char *userbuf,
nat objsize,
PTR object )
MOivget - standard get integer value method The input object location is treated as a signed longnat and retrieved. The output userbuf , has a maximum length of luserbuf that will not be exceeded. If the output is bigger than the buffer, it will be chopped off and MO_VALUE_TRUNCATED returned.
The objsize is ignored.
The offset is treated as a byte offset to the input object . They are added together to get the object location.
Inputs: offset value from the class definition, taken as byte offset to the object pointer where the data is located. objsize the size of the integer, from the class definition. object a pointer to the integer to convert. luserbuf the length of the user buffer. userbuf the buffer to use for output. Outputs: userbuf contains the string of the value of the instance. Returns: OK if the operation succeseded MO_VALUE_TRUNCATED the output buffer was too small, and the string was truncated. other conversion-specific failure status as appropriate. Prototype: STATUS MOivget( nat offset,
nat objsize,
PTR object,
nat luserbuf,
char *userbuf )
MOlongout - output utility for MO methods to put signed longnats Turn the input longnat into a fixed width, 0 padded string and copy it to the output buffer up to a maximum length. Will write a leading minus sign if needed. The fixed width is so string comparisons will yield numeric sort ordering.
Inputs: errstat the status to return if the output buffeer isn't big enough. val the value to write as a string. destlen the length of the user buffer. dest the buffer to use for output Outputs: dest contains a copy of the string value. Returns: OK if the operation succeeded. errstat if the output buffer was too small and the value was chopped off at the end to fit. Prototype: STATUS MOlongout( STATUS errstat, longnat val, nat destlen, char *dest );
MOlstrout - string output with bounded input Copy the input string to the output, knowing the length of both the input and output. If input won't fit, return the given error status. Copy terminates OK on EOS in the input or copying all the characters in the known input length.
Re-entrancy: yes. Inputs errstat value to return on error. srclen maximum length of the source string src the source string destlen length of the output buffer. dest the destination buffer. Outputs: dest gets a copy of the source string. Returns: OK or input errstat value. Prototype: STATUS MOlstrout( STATUS errstat, nat srclen, char *src, nat destlen, char *dest );
MOname_index - standard index for names of attached instances
Method for producing ``index objects whose value is the instance. This is almost like MOidata_index, except that the instdata is filled with a pointer to the instance string (for use with MOstrget) instead of the idata associated with the instance.
The cdata is assumed to point to the classid string. If msg is MO_GET, determine whether the requested instance exists. If it does, fill in instdata with a pointer to the instance string and return OK. If the requested instance does not exist, return MO_NO_INSTANCE.
If the msg is MO_GETNEXT, see if the requested instance exists; if not return MO_NO_INSTANCE. Then locate the next instance in the class. If there is no successor instance in the class, return MO_NO_NEXT. If there is a sucessor, replace the input instance with the one found. Fill in instdata with a pointer to the instance string. If the new instance won't fit in the given buffer (as determined by linstance ), return MO_INSTANCE_TRUNCATED, otherwise return OK.
Inputs: msg either MO_GET or MO_GETNEXT cdata class specific data pointing to the class string. linstance the length of the instance buffer instance the instance in question instdata place to put a pointer to the instance string. Outputs: instdata filled in with a pointer to the instance string. Returns: OK if the operation succeeded. MO_NO_INSTANCE if the requested instance does not exist. MO_NO_NEXT if there is no instance following the specified one in the class. MO_INSTANCE_TRUNCATED if the output instance of a GET_NEXT would not fit in the provided buffer. Prototype: MO_INDEX_METHOD MOname_index;
STATUS MOname_index(nat msg,
PTR cdata,
nat linstance,
char *instance,
PTR *instdata );
MOnoset - standard set method for read-only objects Don't do anything, and return MO_NO_WRITE. Commonly used as the set method for non-writable classids.
Inputs: offset ignored. luserbuf ignored. userbuf ignored. objsize ignored. object ignored. Outputs: object ignored. Returns: MO_NO_WRITE Prototype MO_SET_METHOD MOnoset;
STATUS MOnoset( nat offset,
nat luserbuf,
char *userbuf,
nat objsize,
PTR object )
MOon_off - enable/disable MO attach (for client programs) Turns MOattach off while having calls to it return OK. This is intended to be used by client programs that do not want the expense of MO operations, but which are constructed from libraries that would otherwise define MO objects. All requests return the old state; MO_INQUIRE returns the old state without changing it.
By default, the state is enabled.
Queries with MOget and MOgetnext on objects attached when MO was enabled will always work.
Inputs: operation one of MO_ENABLE. MO_DISABLE, or MO_INQUIRE. Outputs: old_state the previous state, either MO_ENABLED or MO_DISABLED. Returns: OK or other error status. Prototype: STATUS MOon_off( nat operation, nat *old_state );
MOptrget - get pointer at a pointer method Convert the pointer at the object location to a character string. The offset is treated as a byte offset to the input object . They are added together to get the object location.
The output userbuf , has a maximum length of luserbuf that will not be exceeded. If the output is bigger than the buffer, it will be chopped off and MO_VALUE_TRUNCATED returned.
The objsize is ignored.
Inputs: offset value from the class definition, taken as byte offset to the object pointer where the data is located. objsize ignored object a pointer to the pointer to convert. luserbuf the length of the user buffer. userbuf the buffer to use for output. Outputs: userbuf contains the string of the value of the instance. Returns: OK if the operation succeseded MO_VALUE_TRUNCATED the output buffer was too small, and the string was truncated. other conversion-specific failure status as appropriate. Prototype: STATUS MOptrget( nat offset,
nat objsize,
PTR object,
nat luserbuf,
char *userbuf )
MOptrout - output routine for methods to put a pointer value Turn the input PTR into a fixed width, 0 padded string and copy it to the output buffer up to a maximum length. The fixed width is so string comparisons will yield numeric sort ordering.
Inputs: errstat the status to return if the output buffeer isn't big enough. ptr the pointer value to write as a string. destlen the length of the user buffer. dest the buffer to use for output Outputs: dest contains a copy of the string value. Returns: OK if the operation succeeded. errstat if the output buffer was too small and the value was chopped off at the end to fit. Prototype: STATUS MOptrout( STATUS errstat, PTR ptr, nat destlen, char *dest );
MOpvget - get pointer method The input object location is treated as a pointer and retrieved. The output userbuf , has a maximum length of luserbuf that will not be exceeded. If the output is bigger than the buffer, it will be chopped off and MO_VALUE_TRUNCATED returned.
The objsize is ignored.
The offset is treated as a byte offset to the input object . They are added together to get the object location.
Inputs: offset value from the class definition, taken as byte offset to the object pointer where the data is located. objsize ignored. object a pointer. luserbuf the length of the user buffer. userbuf the buffer to use for output. Outputs: userbuf contains the string of the value of the instance. Returns: OK if the operation succeseded MO_VALUE_TRUNCATED the output buffer was too small, and the string was truncated. other conversion-specific failure status as appropriate. Prototype: STATUS MOpvget( nat offset, nat objsize, PTR object, nat luserbuf, char *userbuf )
MOset - set value associated with an instance Attempts to set the value associated with the instance.
If the call succeeds, it must also call the monitors for the class with the MO_SET event, the instance id, and the new value.
Inputs: valid_perms the roles currently in effect, to be and-ed with object permissions to determine access rights. class the class whose value should be altered. instance the instance in question. val pointer to the string containing the new value. Outputs: none Returns: OK if the value was set MO_NO_INSTANCE if the class is not attached MO_NO_WRITE if the class may not be changed. other error status returned by a method. Prototype: STATUS MOset( nat valid_perms,
char *classid,
char *instance,
char *val );
Example: STATUS mysetint( char *classid, char *instance, longnat val ) {
char buf[ 20 ]; CVla( val, buf ); return( MOset( ~0, classid, instance, buf ) );
}
MOset_monitor - set monitor function for a class Arranges to have a monitor function called as a direct result of an MOtell_monitor call or indirectly from other operations. The monitors for a classid and it's twin are kept identical. There may be multiple monitors for a classid. Monitors are installed for both the classid and it's twin. The monitor is uniquely identified by it's classid and mon_data value. (The same mon_data may be used for multiple classids.)
A monitor is deleted by specifying a NULL monitor function for a {classid, mon_data} pair.
The output parameter old_monitor is filled in with the previous monitor for the {classid, mon_data}.
At present the qual_regexp is ignored and all potential calls to the monitor are delivered. In the future (when there's a GL regular expression module to call), the candidate instances will be qualified by the regular expression provided when the monitor was set. It the instance matches, or the expression was NULL, then the monitor would be called.
The monitor is called with the classid, the classid of the twin, if any, the qualified instance, a value, a message type, and the mon_data value.
If the class is not currently defined, the call fails with MO_NO_CLASSID. It may also fail for inability to get memory.
The new monitor function is not called by the MOset_monitor call.
Inputs: classid the classid of the object to be monitored. mon_data data to be handed to the MO_MONITOR_FUNC for the classid. monitor the function to call for events affecting the instance. Outputs: none Returns: OK if the monitor was attached. MO_NO_CLASSID if the classid wasn't defined. MO_BAD_MONITOR if the {classid, mon_data} doesn't exist and the new monitor is NULL (trying to delete one that doesn't exist). MO_MEM_LIMIT_EXCEEDED couldn't allocate memory for the monitor. Prototype: STATUS MOset_monitor( char *classid,
PTR mon_data,
char *qual_regexp
MO_MONITOR_FUNC *monitor
MO_MONITOR_FUNC **old_monitor );
MOstrget - standard get string buffer method Copy the instance string to the output buffer userbuf , to a maximum length of luserbuf . If the output is bigger than the buffer, chop it off and return MO_VALUE_TRUNCATED.
The objsize from the class definition is ignored. The object plus the offset is treated as a pointer to a character string to be copied.
Inputs: offset value from the class definition, taken as byte offset to the object pointer where the data is located. objsize the size of the object from the class definition, ignored. object a pointer to a character string for the instance to copy out. luserbuf the length of the user buffer. userbuf the buffer to use for output. Outputs: userbuf contains a copy of the the string value. Returns: OK if the operation succeseded MO_VALUE_TRUNCATED if the output buffer was too small and the value was chopped off to fit. other method-specific failure status as appropriate. Prototype: MO_GET_METHOD MOstrget;
STATUS MOstrget( nat offset,
nat objsize,
PTR object,
nat luserbuf,
char *userbuf )
MOstrout - output utility for MO methods to put strings Copy the input string to the output buffer up to a maximum length. If the length is exceeded, return the specified error status.
Inputs: errstatus the status to return if the output buffer isn't big enough. str the string to write out l a pointer to a character string for the instance to copy out. luserbuf the length of the user buffer. userbuf the buffer to use for output. Outputs: userbuf contains a copy of the the string value. Returns: OK if the operation succeseded MO_VALUE_TRUNCATED if the output buffer was too small and the value was chopped off to fit. other method-specific failure status as appropriate. Prototype: MO_GET_METHOD MOstrget;
STATUS MOstrget( nat offset,
nat objsize,
PTR object,
nat luserbuf,
char *userbuf )
MOstrpget - standard get string pointer method Copy the string pointed to by instance object to the output userbuf , to a maximum length of luserbuf . If the output is bigger than the buffer, chop it off and return MO_VALUE_TRUNCATED.
The offset and objsize from the class definition are ignored. The object is considered a pointer to a string pointer, and will be dereferenced to find the source string.
Inputs: offset value from the class definition, taken as byte offset to the object pointer where the data is located. objsize the size of the object from the class definition, ignored. object treated as a pointer to a string pointer. luserbuf the length of the user buffer. userbuf the output buffer. Outputs: userbuf contains the string of the value of the instance. Returns: OK if the operation succeseded MO_VALUE_TRUNCATED if the output buffer was too small, and the value was chopped off to fit. other method-specific failure status as appropriate. Prototype: MO_GET_METHOD MOstrpget;
STATUS MOstrpget( nat offset,
nat objsize,
PTR object,
nat luserbuf,
char *userbuf )
MOstrset - standard set string buffer method Copy a caller's string to the buffer for the instance.
The object plus the offset is treated as a pointer to a character buffer having objsize bytes. The input luserbuf is ignored. The string in userbuf is copied up to objsize; if it wouldn't fit, returns MO_VALUE_TRUNCATED, otherwise OK.
Inputs: offset value from the class definition, taken as byte offset to the object pointer where the data is located. luserbuf the length of the user buffer, ignored. userbuf the user string to convert. objsize the size of the output buffer. object interpreted as a character buffer. Outputs: object gets a copy of the input string. Returns: OK if the operation succeseded MO_VALUE_TRUNCATED if the output buffer wasn't big enough. Prototype MO_SET_METHOD MOstrset;
STATUS MOstrset( nat offset,
nat luserbuf,
char *userbuf,
nat objsize,
PTR object );
MOtell_monitor - call class monitor function for an instance Consider call any monitor functions for the classid and it's twin with the specified value and message. The instance provided to the MOtell_monitor call will be qualified by the qual_regexps provided with each monitor instance; only those which match will be called.
If the class is not defined or no monitor exists, returns OK.
Returns the status returned by the called monitor functions. It stops calling monitors when one returns error status. In most cases this should be ignored, because the caller of MOtell_monitor has no idea who is being called.
Prototype: STATUS MOtell_monitor( char *classid, nat instance, char *value, nat msg );
MOuintget - get method for unsigned integer to string Convert the unsigned integer at the object location to a character string. This is often the wrong thing to use, as negative numbers are rare. The offset is treated as a byte offset to the input object . They are added together to get the object location.
The output userbuf , has a maximum length of luserbuf that will not be exceeded. If the output is bigger than the buffer, it will be chopped off and MO_VALUE_TRUNCATED returned.
The objsize comes from the class definition, and is the length of the unsigned integer, one of sizeof(i1), sizeof(i2), or sizeof(longnat).
Inputs: offset value from the class definition, taken as byte offset to the object pointer where the data is located. objsize the size of the integer, from the class definition. object a pointer to the integer to convert. luserbuf the length of the user buffer. userbuf the buffer to use for output. Outputs: userbuf contains the string of the value of the instance. Returns: OK if the operation succeseded MO_VALUE_TRUNCATED the output buffer was too small, and the string was truncated. other conversion-specific failure status as appropriate. Prototype: STATUS MOuintget( nat offset,
nat objsize,
PTR object,
nat luserbuf,
char *userbuf )
MOuintset - standard set unsigned integer method Convert a caller's string to an unsigned integer for the instance.
The offset is treated as a byte offset to the input object . They are added together to get the object location.
The input objsize is the size of the output integer, as in sizeof(i1), sizeof(i2), or sizeof(i4). The object location is taken to be the address of the output. The userbuf contains the string to convert, and luserbuf. is ignored.
Inputs: offset value from the class definition, taken as byte offset to the object pointer where the data is located. luserbuf the length of the user buffer, ignored. userbuf the user string to convert. objsize the size of the integer, from the class definition. object a pointer to the integer. Outputs: object Modified by the method. Returns: OK if the operation succeseded MO_BAD_SIZE if the object size isn't something that can be handled. other conversion-specific failure status as appropriate. Prototype MO_SET_METHOD MOuintset;
STATUS MOuintset( nat offset,
nat luserbuf,
char *userbuf,
nat objsize,
PTR object )
MOuivget - standard get unsigned integer value method The input object location is treated as a unsigned longnat and retrieved. The output userbuf , has a maximum length of luserbuf that will not be exceeded. If the output is bigger than the buffer, it will be chopped off and MO_VALUE_TRUNCATED returned.
The objsize is ignored.
The offset is treated as a byte offset to the input object . They are added together to get the object location.
Inputs: offset value from the class definition, taken as byte offset to the object pointer where the data is located. objsize the size of the integer, from the class definition. object a pointer to the integer to convert. luserbuf the length of the user buffer. userbuf the buffer to use for output. Outputs: userbuf contains the string of the value of the instance. Returns: OK if the operation succeseded MO_VALUE_TRUNCATED the output buffer was too small, and the string was truncated. other conversion-specific failure status as appropriate. Prototype: STATUS MOuivget( nat offset,
nat objsize,
PTR object,
nat luserbuf,
char *userbuf )
MOulongout - output utility for MO methods to put unsigned longnats Turn the input unsigned longnat into a fixed width, 0 padded string and copy it to the output buffer up to a maximum length. The fixed width is so string comparisons will yield numeric sort ordering.
Inputs: errstat the status to return if the output buffeer isn't big enough. val the value to write as a string. destlen the length of the user buffer. dest the buffer to use for output Outputs: dest contains a copy of the string value. Returns: OK if the operation succeeded. errstat if the output buffer was too small and the value was chopped off at the end to fit. Prototype: STATUS MOulongout( STATUS errstat, u_longnat val, nat destlen, char *dest );
MOzeroget - get buffer with zero value method This get method is for use with writable control objects. It writes a buffer of the string of the value zero, as if MOivget had been called with object of zero.
Inputs: offset ignored. objsize ignored. object ignored. luserbuf the length of the user buffer. userbuf the buffer to use for output. Outputs: userbuf Filled with stirng value of zero. Returns: OK if the operation succeseded Prototype: STATUS MOzeroget( nat offset,
nat objsize,
PTR object,
nat luserbuf,
char *userbuf )
MO_INDEX_METHOD - example index method The input cdata is provided from the class definition to allow one index method to be used for multiple classes. If msg is MO_GET, determine whether the requested instance exists. If it does, fill in instdata with a pointer that can be handed to a get or set method, and return OK. If the requested instance does not exist, return MO_NO_INSTANCE.
If the msg is MO_GETNEXT, see if the instance is an empty string. If so, returnthe first instance in the class (or MO_NO_NEXT if there aren't any.) If not, see if the requested instance exists; if it doesn't return MO_NO_INSTANCE. Then locate the next instance in the class. If there is no successor instance in the class, return MO_NO_NEXT. If there is a sucessor, replace the input instance with the one found. Fill in instdata with a pointer appropriate for the get/set methods defined for the class. If the new instance won't fit in the given buffer (as determined by linstance ), return MO_INSTANCE_TRUNCATED, otherwise return OK.
Inputs: msg either MO_GET or MO_GETNEXT cdata class specific data from the class definition. linstance the length of the instance buffer instance the instance in question instdata a pointer to a place to put instance-specific data. Outputs: instdata filled in with appropriate instance-specific data for use by get and set methods. Returns: OK if the operation succeeded. MO_NO_INSTANCE if the requested instance does not exist. MO_NO_NEXT if there is no instance following the specified one in the class. MO_INSTANCE_TRUNCATED if the output instance of a GET_NEXT would not fit in the provided buffer. Prototype: MO_INDEX_METHOD my_index_method;
STATUS my_index_method(nat msg,
PTR cdata,
nat linstance,
char *instance,
PTR *instdata )
MO_GET_METHOD - example get method Convert the internal representation of an object to a character string in userbuf , to a maximum length of luserbuf . If the output is bigger than the buffer, chop it off and return MO_VALUE_TRUNCATED.
The offset and objsize are those from the class definition, and may be used in any way desired to affect the conversion. The object is provided by an index method to identify the instance in question.
Inputs: offset value from the class definition, often taken as byte offset to the object pointer where the data is located. objsize the size of the object, from the class definition. object the object pointer provided by an index method. luserbuf the length of the user buffer. userbuf the buffer to use for output. Outputs: userbuf contains the string of the value of the instance. Returns: OK if the operation succeseded other method-specific failure status as appropriate. Prototype: MO_GET_METHOD my_get_method;
STATUS my_get_method( nat offset,
nat objsize,
PTR object,
nat luserbuf,
char *userbuf )
MO_SET_METHOD - example set method Convert a caller's string to an internal representation of an object. The offset and objsize are those provided by the class definition. The output object is provided by an index method. The input userbuf is of length luserbuf.
Inputs: offset value from the class definition, often taken as byte offset to the object pointer where the data is located. luserbuf the length of the user buffer. userbuf the user string to convert. objsize the size of the object, from the class definition. object the object pointer provided by an index method. Outputs: object May be modified by the method. Returns: OK if the operation succeseded other method-specific failure status as appropriate. Prototype MO_SET_METHOD my_set_method;
STATUS my_set_method( nat offset,
nat luserbuf,
char *userbuf,
nat objsize,
PTR object )
Appendix A: Guide to Writing Objects
A.1: Introduction This appendix provides a guide for writers of MO objects, showing techniques and examples of the approaches that became "obvious" only after a good number were written. This is low-level coding information. We do not talk about the higher level semantics of the objects themselves. This means we don't talk about consistant data views or ways to model transient situations, which will be the subject of another note[4].
Section A.3 with the ways to get and set values. This isn't so bad. The grotty business is handling indexing, which is belabored in Section A.4. Section A.5 talks about ways to organize your code. A brief list of things to avoid is in Section A.6. The obligatory summary in in Section A.7, and references are listed in Section A.8.
A.2: How to use this Appendix
Sliced vertically:
If you want to know how to use the get/set methods, go to section A.3.
If you want to know about indexing and index methods, go to section A.4.
Sliced horizontally:
If you are writing an object for a variable that can be simply read or set go to Section A.3.1.
If you are writing an object for a variable that needs active code to be read or set, go to Section A.3.2.
If you are writing objects for accessing elements of structures, go to Section A.3.3.
If you are writing objects for single global instances, go to section A.4.1.
If you are writing objects for accessing multiple instances of individual objects or structures, go to section A.4.2.
A.3: Value access
One view of MO is that it's a general way of getting and setting the values of named objects. The way that objects are identified are discussed in Section A.4, "Instances and Indexes". This section descirbed the ways you can get and set values once an object is identified. Section A.3.1 describes how you can use the few built-in get/set methods provided by MO for access to program variables. When you need something to happen behind the curtain, you need to provide you own code, which is described in Section A.3.2 on the use of user get/set methods. Section A.3.3 talks about ways to reuse get/set methods when accessing elements of structures.
A.3.1: Simple access to variable using built-in get/set methods
If you have a variable that is a string character buffer or an integer type that you want to make visible, life is pretty simple. MO provides methods for direct access of three different data types: integers, pointers to integers, string buffers, and pointer to string buffers. All you need to do are set up a class that uses them and make an instance of the class appear.
The MO provided methods are listed in Table 6, and each has it's own function documentation.
The first thing you need to do is define an MO class with a call to MOclassdef. For example,
GLOBALDEF longnat My_long;
Somewhere you prepare a class definition, usually as part of an array, as follows: MO_CLASS_DEF My_classes[] = {
{
MO_CDATA_CLASSID, /* flags */
"exp.back.myfacility.my_long", /* classid */
sizeof(My_long), /* size */
MO_READ, /* perms */
0, /* index */
0, /* offset */
MOintget, /* get method */
MOnoset, /* set method */
0, /* cdata */
MOidata_index /* index method */
},
{ 0 }
};
You make this known by calling MOclassdef: stat = MOclassdef( MAXI2, My_classes );
(Use of the array form let's you define all the classes for a module in one call to MOclassdef.) You then declare the instance(s) with a call to MOattach:
stat = MOattach( 0,
"exp.back.myfacility.my_long",
"0",
(PTR)&My_long );
That's all there is to it.
Simple class definition explained Let's look at the class definition in some detail.
{
MO_CDATA_CLASSID, /* flags */
This says to use the classid as the cdata handed to the index method, and to ignore the cdata in the definition. We use this because the MOidata_index method we've chosen to use requires the classid as the cdata.
"exp.back.myfac.my_long", /* classid */
This gives the name of the class. There are conventions for picking names. Unless you are doing something that is intentionally visible to customers, put things into the "exp." space as shown here.
sizeof(My_long), /* size */
This is the size of the objects in the class, which will be handed to get and set methods when they are called.
MO_READ, /* perms */
These are the permissions associated with the object, as defined in the MO spec.
0, /* index */
This is the name of the index class, if any is present. In this case there is no index, so we zero it. (Indexes are used for classes where there will be more than one instance).
0, /* offset */
This is a value handed to the get/set methods on access. The MO provided methods treat it as a byte offset into the object they are handed where the item will be found. This is used to decode structures, which we discuss below.
MOintget, /* get method */
This is the "get" method used to retrieve a value for objects in the class. In this case we are using the MO provided integer method. There are two other MO methods: MOstrget, when the object is a buffer of the size specified, and MOstrpget, where the object is a pointer to a buffer of the specified size.
MOnoset, /* set method */
This is the "set" method used to write values for objects in a class. In this case we do not allow writes, and we use the MO provided method.
0, /* cdata */
This is data handed to the index method below when we are looking up instances in the class. It is usually used to identify the class being indexed if we are using one method to index many classes. The MO provided index methods assume this is the character name of a class that has explicitly attached instances to lookup. This is so common that the "flags" field above supports two special cases: MO_CDATA_CLASSID and MO_CDATA_INDEX, which force the cdata to either the classid or the index value, and ignore the value here. That's what we're doing in this definition.
MOidata_index /* index method */
This is the method function to use to index the class. In this case, we are using the MO provided method for getting instances of objects that have been added with calls to MOattach. If you don't MOattach the instances, you need to provide your own index methods. This is discussed in detail in section A.4.
},
Simple attach explained
Here is a look at the instance attach call.
stat = MOattach( 0,
Flags: There are no modification to this instance. It is plain vanilla. If the instance string were volatile, say if it was constructed in a local buffer that was about to vanish, you'd specify MO_INSTANCE_VAR.
"exp.back.myfacility.my_long",
This is the name of the classid of which this is an instance. It must match the name given in the class definition. The class must be defined before instances are attached.
"0",
This is the identity of the instance in question. By convention, "0" is used for objects that have only one instance. Classes that have more than one instance never use "0" as an instance value.
(PTR)&My_long );
This is a data value handed to the get and set methods for the instance. It is usually a pointer to the appropriate data object.
An even simpler alternative We've shown the use of the MOidata_index and the MOattach call above because it is the useful general case. For our particular example there is a simpler one-step method for defining a single-instance object using a different index method. Index methods are described completely in section A.4.
Here you would use the MOcdata_index rather than MOidata_index. It assumes only instance "0" exists, and that it's instance-specific idata is the cdata in the class definition.
Here is a complete class/instance definition using this technique:
MO_CLASS_DEF My_classes[] = {
{
0, /* flags */
"exp.back.myfacility.my_long", /* classid */
sizeof(My_long), /* size */
MO_READ, /* perms */
0, /* index */
0, /* offset */
MOintget, /* get method */
MOnoset, /* set method */
(PTR)&My_long, /* cdata */
MOcdata_index /* index method */
},
{ 0 }
};
A.3.2: User get/set method functions
Sometimes you will not want to use the built in get or set methods. The job of these methods is to convert back and forth between the string format present at the MO value interfaces to whatever internal representation is used for the object, and cause whatever side-effects the object-writer thinks is appropriate.
You'll write your own get method when you want to decode a field into characters in a way that isn't obvious. You write set methods to allow a complicated conversion, or cause some action to take place when the value is changed. For instance, a writeable cache size object would need a method that did something like lock the cache; flush it; free it's memory; allocate new memory; re-initialize it; and then unlock it.
MO provides utility functions for user-written access methods:
MOstrout
put an string output, checking for the end of the output buffer and returing the error status specified it it won't fit.
MOlongout
put a longnat converted to a string, checking for the end of the output buffer and returing the error status specified it it won't fit. The conversion puts out leading zeros so that lexical sort ordering matches the numeric sort ordering.
MOptrout
put a pointer converted to a string, checking for the end of the output buffers and returning the error status specified if it won't fit. The conversion puts out leading zeros to that lexical sort ordering matches the numeric sort ordering.
MOulongout
put a unsigned longnat converted to a string, checking for the end of the output buffer and returing the error status specified if it won't fit. The conversion puts out leading zeros so that lexical sort ordering matches the numeric sort ordering.
Here is an example of a user get method:
/* offset ignored */
STATUS CS_sem_scribble_check_get(nat gsflags,
nat objsize,
PTR object,
nat luserbuf,
char *userbuf)
{
CS_SEMAPHORE *sem = (CS_SEMAPHORE *)object; char *str;
if( sem->cs_sem_scribble_check == CS_SEM_LOOKS_GOOD )
str = "looks ok";
else if( sem->cs_sem_scribble_check = CS_SEM_WAS_REMOVED )
str = "REMOVED";
else
str = "CORRUPT";
return( MOstrout( MO_VALUE_TRUNCATED, str, luserbuf, userbuf ));
}
A.3.3: Structure member access
Very often you'll have a structure for which you are creating classes for each member. It would be very inefficient to need to attach each member individually, with the instance data being a pointer to the element. Instead, we want to store them in a way that the instance data is a pointer to the entire structure. We could then write access methods for each member, but this is would be a lot of redundant code if there were no special conversions needed.
This situation is cleanly handled by using the "CL_OFFSETOF" macro to set up the "offset" field of the class definition, the "MO_SIZEOF_MEMBER" macro to provide the value for the "size" field, and then using the MO provided access methods. The standard access methods take the class-definition provided offset and add it to the instance data, treating the result as the address of the data element to be converted.
Recall that the CL_OFFSETOF macro provides the byte offset into a structure of a element member in a way suitable for compile time initialization. MO_SIZEOF_MEMBER is an analagous macro that returns the size of the member.
In the example in section A.3.1 all the "offset" fields were set to 0. To provide access to a global structure you might set the classes up using MO_SIZEOF_MEMBER and CL_SIZEOF as shown below.
typedef struct {
longnat field_one;
longnat field_two;
longnat field_three;
} MY_STRUCT;
GLOBALDEF MY_STRUCT My_struct;
MO_CLASS_DEF My_classes[] = {
{
0,
"exp.back.myfacility.my_struct.field_one",
MO_SIZEOF_MEMBER( MY_STRUCT, field_one ),
MO_READ,
0,
CL_OFFSETOF( MY_STRUCT, field_one ),
MOintget,
MOnoset,
(PTR)&My_struct,
MOcdata_index
},
{
0,
"exp.back.myfacility.my_struct.field_two",
MO_SIZEOF_MEMBER( MY_STRUCT, field_two ),
MO_READ,
0,
CL_OFFSETOF( MY_STRUCT, field_two ),
MOintget,
MOnoset,
(PTR)&My_struct,
MOcdata_index
},
{
0,
"exp.back.myfacility.my_struct.field_three",
MO_SIZEOF_MEMBER( MY_STRUCT, field_three ),
MO_READ,
0,
CL_OFFSETOF( MY_STRUCT, field_three )
MOintget,
MOnoset,
(PTR)&My_struct,
MOcdata_index
},
{ 0 }
};
A.4: Instances and indexes
This section describe the way classes are defined regarding their "instance" indexes. Section A.4.1 discusses the simple way of using the MOattach/MOdetach function to use the internal index for single-instance objects. Multiple instance objects in all their complexity are described in section A.4.2.
All classes define the index method that will be used to map instance strings to a PTR of instance-specific data (the idata). They need to handle two messages, MO_GET and MO_GETNEXT.
For MO_GET, the instance string given is the object requested. The index method merely needs to validate the instance and return it's associated idata. The MO_GET case is usually trivial.
The ``interesting case is handling MO_GETNEXT, and we will spend much time discussion ways to create reasonable ordering. Handling MO_GETNEXT message requires validation of the current instance, identification of it's successor (if any), and return of the successor's idata and it's instance string. The successor is defined as instance whose instance string is lexically next greater than the current instance string. As an important special case, if the input instance to a MO_GETNEXT is an empty string (""), then the index method must return the first instance in the class, or MO_NO_NEXT.
MO provides three index methods that are appropriate for most easily forseen cases. .ip MOcdata_index 16 provides a minimal index used to define single instance classes and objects in the class definition. The cdata provided in the class defin