# Originally this was a backup of text input clicketitoggled into ArgoUML # Meanwhile it becomes an intermediate storage for attributes and # class interconnections in the notation of my C stub generator CgeN # (see also end of this text) Model=libdax ClassDiagram=Overview Class=API Author=Thomas Schmitt Version=1.0 Since=11.03.2007 Documentation=\ The API is the only layer visible to the applications. It exposes MMC concepts which it reflects and augments by its own architectural concepts. Subordinates=EQUIP,JOB,AUX Cgen=\ cevapi -r -m struct CevapeqP *equip -r -m struct CevapjoB *job -r -m struct CevapauX *aux -r -m struct CevapgestureS *gestures @ =end Class Class=EQUIP Author=Thomas Schmitt Version=1.0 Since=11.03.2007 Documentation=\ EQUIP represents the physical and logical equipment in reach of libdax. This includes the system, drives, media, and their current states. PeerToPeer=GESTURES Boss=API Cgen=\ cevapeqp -r -v struct CevapI *boss -r -m struct CevapsysteM *sys @ =end Class Class=JOB Author=Thomas Schmitt Version=1.0 Since=11.03.2007 Documentation=\ JOB models the tasks to be performed via libdax. This includes disc, session, track, source, fifo, dewav, burn options. PeerToPeer=GESTURES Boss=API Cgen=\ cevapjob -r -v struct CevapI *boss -r -m struct CevaptodO *todo # >>> @ =end Class Class=AUX Author=Thomas Schmitt Version=1.0 Since=11.03.2007 Documentation=\ AUX bundles any models which are neither EQUIP nor JOB. This includes abort handler and message system. PeerToPeer=GESTURES Boss=API Cgen=\ cevapaux -r -v struct CevapI *boss # >>> @ =end Class Class=GESTURES Author=Thomas Schmitt Version=1.0 Since=11.03.2007 Documentation=\ GESTURES ist the procedural repertoire which interconnects EQUIP, JOB, and AUX and also provides to them the services from the SCSI oriented layers. PeerToPeer=EQUIP,JOB,AUX Subordinates=SCSI_CMD Cgen=\ cevapgestures -r -v struct CevapI *boss # >>> @ =end Class Class=SCSI_CMD Author=Thomas Schmitt Version=1.0 Since=11.03.2007 Documentation=\ SCSI_CMD represents the semantic part of SCSI (i.e. mainly MMC) specs. This layer models each SCSI command that is used by libdax. It knows about its parameters and constraints with particular equipment and jobs. Boss=GESTURES Subordinates=Classes with SCSI_EXEC Interface =end Class Interface=SCSI_EXEC Author=Thomas Schmitt Version=1.0 Since=16.03.2007 Documentation=\ SCSI_EXEC hides the difference between the implementation principle of SCSI format+transport and the principle of SCSI service. Boss=SCSI_CMD Implementations=SCSI_FORMAT,SCSI_SERVICE Cgen=\ cevapsexec -p -v struct CevapsforM *scsi_format -p -v struct CevapsservicE *scsi_service -v int silent_on_scsi_error # >>> @ =end Interface Class=SCSI_FORMAT Author=Thomas Schmitt Version=1.0 Since=11.03.2007 Documentation=\ SCSI_FORMAT translates parameters of SCSI commands into CDBs, takes care for transport and decodes the reply into parameters. Boss=SCSI_CMD via SCSI_EXEC Subordinates=SCSI_TRANSPORT Cgen=\ cevapsform -r -v struct CevapsexeC *boss -p -v struct CevapstransP *scsi_transport # >>> @ =end Class Class=SCSI_TRANSPORT Author=Thomas Schmitt Version=1.0 Since=11.03.2007 Documentation=\ SCSI_TRANSPORT takes a formatted CDB from SCSI_FORMAT and makes the operating system perform a SCSI transaction. It then returns the reply data in raw form. Boss=SCSI_FORMAT Os_specific=yes Cgen=\ cevapstransp -r -v struct CevapsforM *boss # >>> needs thorough rethought -p -v struct Burn_os_transport_drive_elementS *system_dep_drive_info # >>> @ =end Class Class=SCSI_SERVICE Author=Thomas Schmitt Version=1.0 Since=11.03.2007 Documentation=\ SCSI_SERVICE provides the combined services of SCSI_FORMAT and SCSI_TRANSPORT via a set of parametrized functions which abstract SCSI command transactions. Boss=SCSI_CMD via SCSI_EXEC Os_specific=yes Cgen=\ cevapsservice -r -v struct CevapsexeC *boss # >>> needs thorough rethought -p -v struct Burn_os_transport_drive_elementS *system_dep_drive_info # >>> @ =end Class =end ClassDiagram=Overview ClassDiagram=Equip_overview Class=EquipSystem Author=Thomas Schmitt Version=1.0 Since=16.03.2007 Documentation=\ EquipSystem is the inner root class of EQUIP. It describes the system on which libdax is working. This includes the operating system, the system adapter classes, the drives. Boss=EQUIP Subordinates=EquipDrive*N Cgen=\ cevapsystem -r -v struct CevapeqP *boss -r -m char *infotext -r -l struct CevapdrivE *drive -p -v struct CevapdrivE *eol_drive # >>> be boss of SCSI_CMD ? # >>> @ =end Class Class=EquipDrive Author=Thomas Schmitt Version=1.0 Since=16.03.2007 Documentation=\ EquipDrive represents a drive, including its capabilities, its processing status, the media loaded. Subordinates=EquipMedia Boss=EquipSystem Cgen=\ -l cevapdrive -r -v struct CevapsysteM *boss -r -v int global_index -r -m char *devname -r -v int bus_no -r -v int host -r -v int id -r -v int channel -r -v int lun # (ex struct burn_scsi_inquiry_data) -r -v char idata_vendor[9] -r -v char idata_product[17] -r -v char idata_evision[5] -r -v int idata_valid -r -v int phys_if_std -r -m char *phys_if_name -p -v struct CevapsexeC *BURN_OS_TRANSPORT_DRIVE_ELEMENTS -r -v int block_types[4] # (ex struct scsi_mode_data) -p -v int mdata_buffer_size -p -v int mdata_dvdram_read -p -v int mdata_dvdram_write -p -v int mdata_dvdr_read -p -v int mdata_dvdr_write -p -v int mdata_dvdrom_read -p -v int mdata_cdrw_read -p -v int mdata_cdrw_write -p -v int mdata_cdr_read -p -v int mdata_cdr_write -p -v int mdata_simulate -p -v int mdata_max_read_speed -p -v int mdata_max_write_speed -p -v int madata_min_write_speed -p -v int mdata_cur_read_speed -p -v int mdata_cur_write_speed -p -v int mdata_retry_page_length -p -v int mdata_retry_page_valid -p -v int mdata_write_page_length -p -v int mdata_write_page_valid -p -v int mdata_c2_pointers -r -v int mdata_underrun_proof -p -v int mdata_valid # >>> How to handle this by cgen ? : -v pthread_mutex_t access_lock -r -v int current_feat2fh_byte4 -v volatile int released -v struct CevapbuffeR *buffer # >>> next to process: transport.h : struct burn_toc_entry *toc_entry; # >>> transport.h : toc_temp (what is this ? It belongs to BURN_WRITE_RAW) # >>> -r -m struct CevapmediA *media @ =end Class Class=EquipMedia Author=Thomas Schmitt Version=1.0 Since=16.03.2007 Documentation=\ EquipMedia represents an optical disc, including its type, its writeability, its formatting, its available formats and performances. Subordinates=\ EquipProfile*N,EquipFormat*N,EquipPerformance*N,EquipStatus,EquipMulticaps Boss=EquipDrive Cgen=\ cevapmedia -r -v struct CevapdrivE *boss -r -m struct CevapstatuS *status -r -l struct CevapprofilE *profile -p -v struct CevapprofilE *eol_profile -r -v int current_has_feat21h -r -v int current_feat21h_link_size -v int needs_close_session -r -v int bg_format_status -r -v int format_descr_type -r -v off_t format_curr_max_size -r -v unsigned int format_curr_blsas -r -v int best_format_type -r -v off_t best_format_size -r -l struct CevapformaT *format_descriptor -p -v struct CevapformaT *eol_format_descriptor -r -v int nwa -r -v int start_lba -r -v int end_lba -r -m struct CevapmcapS *multicaps # >>> @ =end Class Class=EquipProfile Author=Thomas Schmitt Version=1.0 Since=16.03.2007 Documentation=\ EquipProfile maps a MMC profile into libdax (See mmc5r03c.pdf chapter 5). A profile describes a set of features and may be either current, possible, disabled, or unavailable. Subordinates=EquipFeature*N Boss=EquipMedia Cgen=\ -l cevapprofile -r -v struct CevapmediA *boss -r -v int profile_code -r -v char *profile_text -r -v int is_cd_profile -r -v int is_supported_profile -r -l struct CevapfeaturE *feature -p -v struct CevapfeaturE *eol_feature # >>> @ =end Class Class=EquipFeature Author=Thomas Schmitt Version=1.0 Since=16.03.2007 Documentation=\ EquipFeature maps a MMC feature into libdax (See mmc5r03c.pdf chapter 5). A feature describes a set of SCSI commands and (implicitely) of use cases. Boss=EquipProfile Cgen=\ -l cevapfeature -r -v struct CevapprofilE *boss # >>> @ =end Class Class=EquipFormat Author=Thomas Schmitt Version=1.0 Since= Documentation=\ >>> EquipFormat Boss=EquipMedia Cgen=\ -l cevapformat -r -v struct CevapmediA *boss # >>> @ =end Class Class=EquipPerformance Author=Thomas Schmitt Version=1.0 Since= Documentation=\ >>> EquipPerformance Boss=EquipMedia Cgen=\ -l cevapperf -r -v struct CevapmediA *boss # >>> @ =end Class Class=EquipStatus Author=Thomas Schmitt Version=1.0 Since=17.3.2007 Documentation=\ EquipStatus represents the status of media and drive. This includes blank/appendable/closed, progress indicator. Boss=EquipMedia Cgen=\ cevapstatus -r -v struct CevapmediA *boss -v int status -m char *status_text -v volatile int busy -v struct CevapprofilE *current_profile -v int complete_sessions -v int last_track_no -v off_t media_capacity_remaining -v int media_lba_limit -v struct CevapprogresS *progress # >>> @ =end Class Class=EquipMulticaps Author=Thomas Schmitt Version=1.0 Since=14.8.2007 Documentation=\ EquipMulticaps represents media dependent properties and media states. This includes eventually existing sessions, closure status, profile dependent capabilities. Boss=EquipMedia Cgen=\ cevapmcaps -r -m struct CevapdisC *disc # >>> @ =end Class Class=EquipTocItem Author=Thomas Schmitt Version=1.0 Since=14.8.2007 Boss= Cgen=\ -l cevaptocitem -r -v struct CevapdisC *boss -v int session -v int valid -v int control # obscure info from CD TOC : possibly length of track -v unsigned char point -v unsigned char min -v unsigned char sec -v unsigned char frame # -v int pmin -v int psec -v int pframe # -v int start_lba -v int track_blocks @ =end Class =end ClassDiagram=Equip_overview ClassDiagram=Job_overview Class=JobTodo Author=Thomas Schmitt Version=1.0 Since=18.3.2007 Documentation=\ JobTodo records what is to be done during a job. This includes peripheral actions like tray load/eject and central actions like blank, format, burn. Subordinates=JobDisc,JobOptions Cgen=\ cevaptodo -v volatile int cancel # >>> @ =end Class Class=JobDisc Author=Thomas Schmitt Version=1.0 Since=18.3.2007 Documentation=\ JobDisc models a disc structure. Either one which already exists or one which is to be created in a job run. Subordinates=JobSession*N Boss=JobTodo Cgen=\ cevapdisc -l struct CevapsessioN *session -r -v struct CevapsessioN *eol_session -l struct CevaptociteM *toc_entry -r -v struct CevaptociteM *eol_toc_entry # >>> take over services of struct burn_disc @ =end Class Class=JobSession Author=Thomas Schmitt Version=1.0 Since=18.3.2007 Documentation=\ JobSession represents a recording session. A session usually bundles several tracks. Traditionally the last session of a disc is recognized by operating systems as the thing to be mounted. Subordinates=JobTrack*N,JobFifo Boss=JobDisc Cgen=\ -l cevapsession -r -v struct CevapdisC *boss # >>> -l struct CevaptracK *track -r -v struct CevaptracK *eol_track # >>> @ =end Class Class=JobTrack Author=Thomas Schmitt Version=1.0 Since=18.3.2007 Documentation=\ JobTrack represents a track to be recorded. A track mainly is associated with a data source but in many cases it also becomes a recognizable entity on the target media. Subordinates=JobBlock*N,JobTrackFilter,JobSource Boss=JobSession Cgen=\ -l cevaptrack -r -v struct CevapsessioN *boss # >>> @ =end Class Class=JobBlock Author=Thomas Schmitt Version=1.0 Since=18.3.2007 Documentation=\ JobBlock represents a single output data transaction unit. On CD this is the same as an addressable media block resp. sector. On DVD this might be an addressable block od 2k or a packet of e.g. 32k. Boss=JobTrack Cgen=\ cevapblock -v int alba -v int rlba # >>> @ =end Class Class=JobSource Author=Thomas Schmitt Version=1.0 Since=8.4.2007 Documentation=\ JobSource represents a data source for a track. Typically this is a disk file or a stream file descriptor like stdin. Subordinates=JobSourceBlock*N Boss=JobTrack =end Class Class=JobSourceBlock Author=Thomas Schmitt Version=1.0 Since=8.4.2007 Documentation=\ JobSourceBlock represents a single input data transaction unit. Boss=JobSource =end Class Class=JobFifo Author=Thomas Schmitt Version=1.0 Since=8.4.2007 Documentation=\ JobFifo reads data via JobTrackFilter and buffers them until JobBlock can accept them. Boss=JobSession =end Class Class=JobTrackFilter Author=Thomas Schmitt Version=1.0 Since=8.4.2007 Documentation=\ JobTrackFilter reads data from JobSourceBlock, processes them and presents them to JobFifo or JobBlock. This includes stripping of .wav headers. Boss=JobTrack =end Class Class=JobOptions Author=Thomas Schmitt Version=1.0 Since=18.3.2007 Documentation=\ JobOptions bundles the adjustable parameters of a job. This includes dummy mode, speed, appendability, blank mode, format selection, write mode, underrun protection, random access addressing. Boss=JobTodo Cgen=\ cevapjobopts # >>> -v int wait_for_buffer_free -v unsigned int wfb_min_usec -v unsigned int wfb_max_usec -v unsigned int wfb_timeout_sec -v unsigned int wfb_min_percent -v unsigned int wfb_max_percent # >>> -m struct params params (used by disabled read cd funtionality) @ =end Class Class=JobBuffer Author=Thomas Schmitt Version=1.0 Since=13.8.2007 Documentation=\ JobBuffer is an intermediate storage for the content of several JobBlock or JobSourceBlock. Cgen=\ cevapbuffer # >>> @ =end Class Class=JobProgress Author=Thomas Schmitt Version=1.0 Since=13.8.2007 Documentation=\ JobProgress reflects the state and parts of the history of a job Cgen=\ cevapprogress -v int nominal_write_speed -v off_t pessimistic_buffer_free -v int pbf_altered -v unsigned int pessimistic_writes -v unsigned int waited_writes -v unsigned int waited_tries -v unsigned int waited_usec # >>> the info provided by struct burn_progress # >>> @ =end Class Class= Author=Thomas Schmitt Version=1.0 Since= Documentation=\ =end Class =end ClassDiagram=Equip_overview # >>> a dummy to be integrated into the model Cgen=\ burn_os_transport_drive_elements # >>> @ =end Model=libdax ---------------------------------------------------------------------------- Notes: ---------------------------------------------------------------------------- Generate C stubs: test_dir=...where_to_generate_the_stub... model_dir=...where_to_find_the_model_file_libdax_model.txt... xtr_dir=...where_to_find_the_extractor_script_extract_cgen_input.sh... cgen_dir=...where_to_find_the_cgen_binary... /bin/rm "$test_dir"/cevap*.[cho] \ "$test_dir"/burn_os_transport_drive_elements*.[cho] \ "$test_dir"/a.out cd "$test_dir"/ cat "$model_dir"/libdax_model.txt | \ "$xtr_dir"/extract_cgen_input.sh | \ "$cgen_dir"/cgen -smem_local -ansi -global_include cevap_global.h Compile: ( cd "$test_dir" ; cc -g -c *.c 2>&1 | less ) ---------------------------------------------------------------------------- "$xtr_dir"/extract_cgen_input.sh : #!/bin/sh copy_mode=0 while true do read line if test "$copy_mode" = "0" then if echo " $line" | grep '^ Cgen=' >/dev/null 2>&1 then copy_mode=1 if echo " $line" | grep '^ Cgen=..' >/dev/null 2>&1 then echo " $line" | sed -e 's/^ Cgen=//' fi elif echo " $line" | grep '^ =end Model=' >/dev/null 2>&1 then break fi else if test " $line" = " @" then copy_mode=0 echo "@" else echo " $line" | sed -e 's/^ //' fi fi done ---------------------------------------------------------------------------- Description of CgeN cgen produces a class stub in C programming language. The data structure of the class is described by some lines which get read from stdin. The stub will consist of two files .h and .c which emerge in the current working directory. It will define a struct for representing the class data aspects, construtor _new(), destructor _destroy(), getter __get() for each structure element. Some more functions get added for particular class and element roles. After first generation, there is no further support by cgen. It simply refuses to overwrite existing files because it supposes that those contain code added by the human programmer. Those programmer enhancements are supposed to include explanatory comments, class specific methods, initial element values and other special precautions within the generated functions. Command line options -no_stic prevents usage of stic_dir/s_tools/*.[ch] -ansi generates ANSI C function heads and makes file .h hold only public definitions: an opaque declaration of the class struct and a list of function prototypes. The definiton of the class struct is then in _private.h . -global_include filename sets the name of a file which will contain globally necessary declarations. Currently it lists the existence of all class structs. A class can have one of two roles: - Standalone class. Input example: my_class - Listable class, which has pointers to peer instances: .prev and .next Such classes get a list destructor _destroy_all() which destroys all members of a list (which is given by any of the list members). Such a class should have a pointer *boss as first element in which case the constructor will look like _new(struct **o,struct *boss,int flag); There is a function _link() which inserts an instance into a list and a function _count() which tells the number of list members. Input example: -l my_class A modifier is defined for listable classes: - Bossless listable. cgen will not warn if the first element is not struct *boss and will not include a parameter *boss into the constructor. I.e. it will look like the constructor of non-listable classes: _new(struct **o, int flag); Elements have one of the following roles: - Value. It provides only storage for a C data type (which may be a C pointer despite the role name "value"), a getter method __get(), and a setter method __set(). Input examples: -v int i -v int a[100] -v char *cpt -v struct xyz x -v struct xyz *xpt - Managed. This has to be a pointer to a struct or to char. It will not get attached to an object by the stub's code but its destructor _destroy() will be called by _destruct(). In case of (char *) it is supposed that a non-NULL value has been allocated by malloc(). Managed (char *) types get a setter function __set() which allocates memory and copies the textstring from its parameter. Input examples: -m struct XyZ *xyzpt -m char *textstring - Chainlink. A pair of prev-next-style pointers to the own class struct. Function _destruct() will unlink the affected instance and put together its link partners. Input example (there must always be two consequtive -c lines): -c struct My_clasS *up -c struct My_clasS *down - List. A pair of pointers to the struct of a listable class. The first one holds the start of the list, the second one holds the end. For insertion of list items there is provided method _new_(). The inserted item is then content of the pointer. _destroy() instance calls _destroy_all(). There is a method _set_() which should be used with caution, if ever. Input example (there must always be a -l and a -v line): -l struct XyZ *list_start -v struct XyZ *list_end The availability of getter method _get_(), and setter method _set__set() can be controled by two modifiers: - Readonly. Only a getter method. Input example -r -v int broadcasted_status - Private. Neither getter nor setter method. Input example -p -v int private_value - Bossless listable. This marks elements which are listable objects but do not expect a boss pointer in their constructor. See above: Listable class and the bossless listable modifier for classes. Input example -b -l struct XyZ *list -v struct XyZ *last_in_list Example run: rm class_x.c class_x.h class_y.c class_y.h bin/cgen <<+ -l class_x -r -v struct Boss_clasS *boss -v int x -r -v struct stat stbuf -m struct Class_Y *y -m char *text -c struct Class_X *master -c struct Class_X *slave -b -l struct Class_X *provider -r -v struct Class_X *last_provider @ -b -l class_y -r -v char providername[80] @ + ------------------------------------------------------------------------ The generated code uses smem.[ch] out of one of my BSD licensed projects. Out of smem.h : smem Functions to replace malloc() and free() in order to get more control over memory leaks or spurious errors caused by faulty usage of malloc() and free(). Sourcecode provisions: Use only the following macros for memory management: TSOB_FELD(type,count) creates an array of items of given type Smem_malloC() analogue of malloc() Smem_freE() analogue of free() One may #define malloc Smem_malloC resp. #define free Smem_freE but better would be to review (and often to streamline) the sourcecode in respect to those two functions. Speed versus control: In production versions, where maximum speed is required, one may undefine the macro Smem_own_functionS in smem.h . This causes the above macros to directly invoke malloc() and free() without any speed reduction (and without any additional use). Undefinitio can be done globaly by modifying smem.h or locally by defining Smem_no_own_functionS before including smem.h . If Smem_own_functionS remains defined, then the functions Smem_malloc() Smem_free() are used rather than malloc() and free(). They count the number of calls to maintain a rough overview of memory usage. Smem_malloc() additionally checks for 0 size and Smem_free() checks for NULL pointers, which they both report to stderr. Eventually one should set a breakpoint in function Smem_protest() to learn about the origin of such messages. A status line may be obtained by Smem_report() or printed by Smem_stderr(). As long as the variable Smem_record_itemS is set to 0, there is not very much overhead compared with malloc() and free(). If the variable is set to 1 by Smem_set_record_items() then all malloc() results are kept in a list where they will be deleted by their corresponding Smem_free() calls. If a pointer is to be freed, which is not recorded in the list then an error message will be printed to stderr. The memory will not be freed ! This mode not only may be very slow, it also consumes at least 16 byte per piece of data which was obtained by malloc as long as it has not been freed. Due to the current nature of the list, large numbers of memory items are freed much faster in the reverse order of their creation. If there is a list of 100000 strings to delete, it is very rewarding to free the youngest ones first. A shortcut via hashing is available but consumes 24 bytes rather than 16. (see above Smem_with_hasH ) The function Smem_is_recorded() can be used to check wether a pointer is valid according to the list. It returns : 0 = is not in list , 1 = is in list , 2 = recording is off If one decides to start recording malloc() results in the midst of a program run, one has to be aware of false protests of Smem_free() if a memory piece has been allocated before recording started. This will also cause those pieces to be memory leaks because Smem_free() refuses to delete them. (Freeing memory that was not obtained by malloc or was already freed previously can result in deferred SIGSEGV or similar trouble, depending on OS and library.) Also in that case one should stop recording before ending the program, to avoid a lot of false complaints about longliving memory objects.