ARPDAS_QNX6 1.0
|
00001 // Include DG_data.h first here to make sure our definition of 00002 // IOFUNC_ATTR_T gets used in this file 00003 #include "DG_data.h" 00004 #include <unistd.h> 00005 #include <errno.h> 00006 #include <sys/types.h> 00007 #include <sys/stat.h> 00008 #include <fcntl.h> 00009 #include <string.h> 00010 #include <ctype.h> 00011 #include <limits.h> 00012 #include <stdlib.h> 00013 #include "nortlib.h" 00014 #include "nl_assert.h" 00015 #include "tm.h" 00016 00017 resmgr_connect_funcs_t DG_data::connect_funcs; 00018 resmgr_io_funcs_t DG_data::io_funcs; 00019 bool DG_data::funcs_initialized = false; 00020 bool DG_data::quitting = false; 00021 00022 extern "C" { 00023 static struct data_dev_ocb *ocb_calloc(resmgr_context_t *ctp, 00024 data_dev_attr *device); 00025 static void ocb_free(struct data_dev_ocb *ocb); 00026 } 00027 00028 static iofunc_funcs_t ocb_funcs = { 00029 _IOFUNC_NFUNCS, 00030 ocb_calloc, 00031 ocb_free 00032 }; 00033 00034 static iofunc_mount_t DGdata_mountpoint = { 0, 0, 0, 0, &ocb_funcs }; 00035 00036 static struct data_dev_ocb *ocb_calloc(resmgr_context_t *ctp, 00037 data_dev_attr *device) { 00038 struct data_dev_ocb *ocb = 00039 (struct data_dev_ocb *) 00040 malloc(sizeof(struct data_dev_ocb)); 00041 ocb->rcvid = 0; 00042 ocb->msgsize = 0; 00043 return ocb; 00044 } 00045 00046 static void ocb_free(struct data_dev_ocb *ocb) { 00047 free(ocb); 00048 } 00049 00050 00051 00052 00053 DG_data::DG_data(DG_dispatch *dispatch, const char *name_in, void *data, 00054 int data_size, int synch) 00055 : DG_dispatch_client() { 00056 00057 dispatch_t *dpp = dispatch->dpp; 00058 name = name_in; 00059 dptr = data; 00060 dsize = data_size; 00061 synched = synch; 00062 stale_count = 0; 00063 data_attr.written = false; 00064 00065 // This is our write-only command interface 00066 resmgr_attr_t resmgr_attr; 00067 memset(&resmgr_attr, 0, sizeof(resmgr_attr)); 00068 resmgr_attr.nparts_max = 1; 00069 resmgr_attr.msg_max_size = data_size; 00070 data_attr.DGd = this; 00071 00072 // io_funcs and connect_funcs are static, so we only need ot do this once, 00073 // but it won't hurt to do it more than once 00074 if ( !funcs_initialized ) { 00075 iofunc_func_init(_RESMGR_CONNECT_NFUNCS, &connect_funcs, 00076 _RESMGR_IO_NFUNCS, &io_funcs ); 00077 io_funcs.write = DG_data_io_write; 00078 io_funcs.notify = DG_data_io_notify; 00079 io_funcs.close_ocb = DG_data_io_close_ocb; 00080 //io_funcs.unblock = DG_data_io_unblock; 00081 funcs_initialized = true; 00082 } 00083 00084 iofunc_attr_init( &data_attr.attr, S_IFNAM | 0222, 0, 0 ); // write-only 00085 data_attr.attr.mount = &DGdata_mountpoint; 00086 IOFUNC_NOTIFY_INIT( data_attr.notify ); 00087 char tbuf[80]; 00088 snprintf(tbuf, 79, "DG/data/%s", name); 00089 const char *wr_devname = tm_dev_name( tbuf ); 00090 dev_id = resmgr_attach( dpp, &resmgr_attr, wr_devname, _FTYPE_ANY, 0, 00091 &connect_funcs, &io_funcs, &data_attr ); 00092 if ( dev_id == -1 ) 00093 nl_error( 3, "Unable to attach name %s: errno %d", wr_devname, errno ); 00094 00095 attach(dispatch); // Now get in on the quit loop 00096 } 00097 00098 DG_data::~DG_data() {} 00099 00100 // The semantics of write are a bit non-standard. I use blocking I/O 00101 // purely as a synchronization technique. In all contexts, a write 00102 // that gets here is immediately processed, but depending on 00103 // the synchronization flag (set in the TMC source) and the nonblock 00104 // value (set by the client), we may not reply immediately to the 00105 // client. 00106 int DG_data::io_write( resmgr_context_t *ctp, IOFUNC_OCB_T *ocb, 00107 int nonblock ) { 00108 int msgsize = quitting ? 0 : 00109 resmgr_msgread( ctp, dptr, dsize, sizeof(io_write_t) ); 00110 data_attr.written = synched; 00111 if (!quitting && synched && !nonblock) { 00112 if (blocked && blocked != ocb) 00113 return EBUSY; 00114 ocb->rcvid = ctp->rcvid; 00115 ocb->msgsize = msgsize; 00116 blocked = ocb; 00117 return _RESMGR_NOREPLY; 00118 } 00119 _IO_SET_WRITE_NBYTES( ctp, msgsize ); 00120 stale_count = 0; 00121 return EOK; 00122 } 00123 00124 void DG_data::synch() { 00125 data_attr.written = false; 00126 if (blocked) { 00127 MsgReply(blocked->rcvid, blocked->msgsize, 0, 0); 00128 blocked = 0; 00129 } 00130 if (IOFUNC_NOTIFY_OUTPUT_CHECK( data_attr.notify, 1 ) ) 00131 iofunc_notify_trigger(data_attr.notify, 1, IOFUNC_NOTIFY_OUTPUT); 00132 } 00133 00134 int DG_data::stale(int max_stale) { 00135 int rv = stale_count; 00136 if ( stale_count < INT_MAX ) ++stale_count; 00137 if ( rv > max_stale ) rv = max_stale; 00138 return rv; 00139 } 00140 00141 int DG_data_io_write( resmgr_context_t *ctp, 00142 io_write_t *msg, IOFUNC_OCB_T *ocb ) { 00143 int status, nonblock; 00144 00145 status = iofunc_write_verify(ctp, msg, (iofunc_ocb_t *)ocb, &nonblock); 00146 if ( status != EOK ) 00147 return status; 00148 00149 if ((msg->i.xtype &_IO_XTYPE_MASK) != _IO_XTYPE_NONE ) 00150 return ENOSYS; 00151 00152 return ocb->hdr.attr->DGd->io_write(ctp, ocb, nonblock); 00153 } 00154 00155 int DG_data_io_notify( resmgr_context_t *ctp, 00156 io_notify_t *msg, IOFUNC_OCB_T *ocb ) { 00157 IOFUNC_ATTR_T *wr_attr = ocb->hdr.attr; 00158 int trig = 0; 00159 if (!wr_attr->written) trig |= _NOTIFY_COND_OUTPUT; 00160 return(iofunc_notify(ctp, msg, wr_attr->notify, trig, NULL, NULL )); 00161 } 00162 00163 int DG_data_io_close_ocb(resmgr_context_t *ctp, void *rsvd, 00164 IOFUNC_OCB_T *ocb) { 00165 IOFUNC_ATTR_T *wr_attr = ocb->hdr.attr; 00166 iofunc_notify_remove(ctp, wr_attr->notify); 00167 return(iofunc_close_ocb_default(ctp, rsvd, &ocb->hdr)); 00168 } 00169 00170 /** DG_data::ready_to_quit() returns true if we are ready to terminate. For DG/data, that means all writers 00171 have closed their connections and we have detached the device. 00172 */ 00173 int DG_data::ready_to_quit() { 00174 // unlink the name 00175 quitting = true; 00176 if ( dev_id != -1 ) { 00177 int rc = resmgr_detach( dispatch->dpp, dev_id, _RESMGR_DETACH_PATHNAME ); 00178 if ( rc == -1 ) 00179 nl_error( 2, "Error returned from resmgr_detach: %d", errno ); 00180 dev_id = -1; 00181 } 00182 if ( data_attr.attr.count ) 00183 nl_error( -2, "Still waiting for DG/data/%s", name ); 00184 return data_attr.attr.count == 0; 00185 }