qnx之resource manager(三)

qnx之resource manager(三)
device-specific and per-open data
学习目的
1.举例引入概念
2.代码编写步骤

1.举例引入概念
a time resource manager,如下所示:
qnx之resource manager(三)_第1张图片
该resource manager必须要有以下特性:
1.操作多个设备
•/dev/time/now
•/dev/time/min
•/dev/time/hour

2.在read时,能返回多个数据
•返回一次数据
•在后面的reads中,返回0以表示读到了文件的最后

3.维护open和read之间的上下文
注:要实现以上需求,必须要满足以下要求:a.name和device的数量都知道;b.device的数量不是特别大(少于100)

2.代码编写步骤:
1.注册这3个新name

resmgr_attach (dpp, &rattr, “/dev/time/now”,
_FTYPE_ANY, 0, &connect_funcs, &io_funcs, &nowattr);
resmgr_attach (dpp, &rattr, “/dev/time/hour”,
_FTYPE_ANY, 0, &connect_funcs, &io_funcs, &hourattr);
resmgr_attach (dpp, &rattr, “/dev/time/min”,
_FTYPE_ANY, 0, &connect_funcs, &io_funcs, &minattr);
   
   
   
   
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

或者

char *devnames [NumDevices] = { … initializers … };
…
for (i = 0; i < NumDevices; i++) {
resmgr_attach (…, devnames [i], …);
}
   
   
   
   
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5

图解:
qnx之resource manager(三)_第2张图片

2.编写I/O和connect 函数相关
qnx之resource manager(三)_第3张图片
每一个open()都匹配一个ocb,并且指向我们打开的设备的attribute structure。
attribute structure指向更高级别的structure(mount structure),它描述了 普通mountpoint 信息。

重写attr,以包含我们自己的数据:

struct Timeattr_s;
#define IOFUNC_ATTR_T struct Timeattr_s
#include 
#include 
typedef struct Timeattr_s {
iofunc_attr_t attr; // encapsulate iofunc layer’s
// attr
char * format; // our data
} Timeattr_
   
   
   
   
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

导致io_open函数原型变化:

int io_open (..., RESMGR_HANDLE_T *handle, ...)
变为
int io_open (..., Timeattr_t *tattr, ...)
   
   
   
   
   
   
   
   
  • 1
  • 2
  • 3

重写ocb,以包含我们自己的数据:

struct Timeocb_s;
#define IOFUNC_OCB_T struct Timeocb_s
#include 
#include 
typedef struct Timeocb_s {
iofunc_ocb_t ocb; // encapsulate iofunc layer’s ocb
char *buffer; // for buffer of data we return
int bufsize; // how many bytes are in buffer
} Timeocb_t;
   
   
   
   
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

使io_read函数原型变化:

int io_read (..., RESMGR_OCB_T *ocb)
变为
int io_read (..., Timeocb_t *tocb)
   
   
   
   
   
   
   
   
  • 1
  • 2
  • 3

ocb的动态分配和释放
1:先定义iofunc_funcs_t结构体,
2:然后将该结构体地址放入iofunc_mount_t结构体中,
3:再将iofunc_mount_t结构体地址放入iofunc_attr_t

IOFUNC_OCB_T *time_ocb_calloc (resmgr_context_t *ctp,
IOFUNC_ATTR_T *attr)  //由iofunc_open_default()函数调用
void time_ocb_free (IOFUNC_OCB_T *ocb)//由iofunc_close_ocb_default()函数调用

Timeocb_t *
time_ocb_calloc (resmgr_context_t *ctp, Timeattr_t *tattr)
{
    Timeocb_t *tocb;
    tocb = calloc (1, sizeof (Timeocb_t));
    // do anything else to our per ocb data
    tocb -> buffer = NULL;
    return tocb;
}
void
time_ocb_free (Timeocb_t *tocb)
{
    if (tocb -> buffer) {
    free (tocb -> buffer);
    }
    free (tocb);
}

//1
iofunc_funcs_t time_ocb_funcs = {
_IOFUNC_NFUNCS,
time_ocb_calloc,
time_ocb_free
};

//2
iofunc_mount_t time_mount = { 0, 0, 0, 0, &time_ocb_funcs };

//3
for (i = 0; i < NUMDEVICES; i++) {
iofunc_attr_init (&timeattrs [i].attr, ...);
timeattrs [i].attr.mount = &time_mount;
timeattrs [i].format = formats[i];
resmgr_attach (dpp, &rattr, devnames [i], _FTYPE_ANY, 0,
&connect_funcs, &io_funcs,
&timeattrs [i]);
}
   
   
   
   
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41

注:系统中有
typedef struct _iofunc_ocb {
IOFUNC_ATTR_T *attr;

} iofunc_ocb_t;
所以iofunc_ocb_t包含了我们重写的IOFUNC_ATTR_T,并且IOFUNC_ATTR_T包含了iofunc_attr_t

以上几个结构体包含关系如图:
qnx之resource manager(三)_第4张图片

总体代码:


/*
 *  time.c
 *
 *  This module contains the source code for the /dev/time
 *  resource manager.  This illustrates returning data to a client
 *  that is different on a per-device basis.
 *
 *  This module contains all of the functions necessary.
 *
*/

#include 
#include 
#include 
#include 
#include 

/*
 * we are extending the ocb and the attr (Timeocb_s and Timeattr_s are
 * really Timeocb_t and Timeattr_t below)
*/

struct Timeattr_s;
#define IOFUNC_ATTR_T   struct Timeattr_s
struct Timeocb_s;
#define IOFUNC_OCB_T    struct Timeocb_s

#include 
#include 
#include 
#include 

/*
 *  Define our device attributes structure.
*/

typedef struct Timeattr_s {
    iofunc_attr_t   attr;
    char *          format;     // output format of each device
} Timeattr_t;

/*
 *  Define our open context block structure.
*/

typedef struct Timeocb_s {
    iofunc_ocb_t    ocb;        // this has 'IOFUNC_ATTR_T *attr' at its top
                                // (ocb.offset is the current position
                                // in the buffer)
    char            *buffer;    // the data returned to the client
    int             bufsize;    // the size of the buffer
} Timeocb_t;

/*
 * Number of devices, and how long or format strings are allowed to be.
*/

#define NUMDEVICES  3

#define MAX_FORMAT_SIZE   64

/*
 *  Declare the tables used by the resource manager.
*/

/* for a shared target, please change the time directory to something
 *  unique.
 */

#define TIME_DIR "/dev/time"
//#define TIME_DIR "/david/time"

//  device names table
char    *devnames [NUMDEVICES] =
{
    TIME_DIR "/now",            // offset HNow
    TIME_DIR "/hour",           // offset HHour
    TIME_DIR "/min"             // offset HMin
};

//  formats for each device
char    formats [NUMDEVICES][MAX_FORMAT_SIZE + 1] =
{
    "%Y %m %d %H:%M:%S\n",
    "%H\n",
    "%M\n"
};

//  pathname ID table
int         pathnameID [NUMDEVICES];

//  device information table
Timeattr_t  timeattrs [NUMDEVICES];

/*
 *  some forward declarations
*/

void options (int argc, char **argv);

//  I/O functions
int io_read (resmgr_context_t *ctp, io_read_t *msg, Timeocb_t *tocb);
int io_write (resmgr_context_t *ctp, io_write_t *msg, Timeocb_t *tocb);
Timeocb_t *time_ocb_calloc (resmgr_context_t *ctp, Timeattr_t *tattr);
void time_ocb_free (Timeocb_t *tocb);

//  miscellaneous support functions
char *format_time (char *format, int time_offset);
/*
 *  our connect and I/O functions
*/

resmgr_connect_funcs_t  connect_funcs;
resmgr_io_funcs_t       io_funcs;

/*
 *  our ocb allocating and freeing functions
*/

iofunc_funcs_t          time_ocb_funcs = {
    _IOFUNC_NFUNCS,
    time_ocb_calloc,
    time_ocb_free
};

/*
 *  the mount structure, we only have one so we statically declare it
*/

iofunc_mount_t          time_mount = { 0, 0, 0, 0, &time_ocb_funcs };

/*
 *  our dispatch, resource manager and iofunc variables
*/

dispatch_t              *dpp;
resmgr_attr_t           rattr;
dispatch_context_t      *ctp;

/*
 *  some miscellaneous variables
*/

char    *progname = "time";                // for diagnostic messages
int     optv;                               // -v for verbose operation

int main (int argc, char **argv)
{
    int i;

    printf ("%s:  starting...\n", progname);

    options (argc, argv);

    dpp = dispatch_create ();
    memset (&rattr, 0, sizeof (rattr));

    /*
     * initialize the connect functions and I/O functions tables to
     * their defaults and then override the defaults with the
     * functions that we are providing.
    */

    iofunc_func_init (_RESMGR_CONNECT_NFUNCS, &connect_funcs,
                      _RESMGR_IO_NFUNCS, &io_funcs);
    io_funcs.read = io_read;
    io_funcs.write = io_write;

    /*
     *  call resmgr_attach to register our 3 prefixes with the
     *  process manager, and also to let it know about our connect
     *  and I/O functions.
     *
     *  On error, returns -1 and errno is set.
    */

    for (i = 0; i < NUMDEVICES; i++) {
        if (optv) {
            printf ("%s:  attaching pathname %s\n", progname, devnames [i]);
        }

        /* 
         *  for this sample program we are using the same mount structure
         *  for all devices, we are using it solely for providing the
         *  addresses of our ocb calloc and free functions.
        */

        iofunc_attr_init (&timeattrs [i].attr, S_IFCHR | 0666, NULL, NULL);
        timeattrs [i].attr.mount = &time_mount;
        timeattrs [i].format = formats[i];
        pathnameID [i] = resmgr_attach (dpp, &rattr, devnames [i],
                    _FTYPE_ANY, 0, &connect_funcs, &io_funcs, &timeattrs [i]);

        if (pathnameID [i] == -1) {
            fprintf (stderr, "%s:  couldn't attach pathname %s, errno %d\n",
                             progname, devnames [i], errno);
            exit (1);
        }
    }

    if (optv) {
        printf ("%s:  entering dispatch loop\n",
                progname);
    }

    ctp = dispatch_context_alloc (dpp);

    while (1) {
        if ((ctp = dispatch_block (ctp)) == NULL) {
            fprintf (stderr, "%s:  dispatch_block failed: %s\n",
                             progname, strerror (errno));
            exit (1);
        }
        dispatch_handler (ctp);
    }
}

/*
 *  time_ocb_calloc
 *
 *  The purpose of this is to give us a place to allocate our own ocb.
 *  It is called as a result of the open being done
 *  (e.g. iofunc_open_default causes it to be called).  We register
 *  it through the mount structure.
*/

Timeocb_t *
time_ocb_calloc (resmgr_context_t *ctp, Timeattr_t *tattr)
{
    Timeocb_t   *tocb;

    if (optv) {
        printf ("%s:  in time_ocb_calloc \n", progname);
    }

    if ((tocb = calloc (1, sizeof (Timeocb_t))) == NULL) {
        if (optv) {
            printf ("%s:  couldn't allocate %d bytes\n",
                    progname, sizeof (Timeocb_t));
        }
        return (NULL);
    }
    // do anything else to our part of the ocb we wish
    tocb -> buffer = NULL;
    return (tocb);
}

/*
 *  time_ocb_free
 *
 *  The purpose of this is to give us a place to free our ocb.
 *  It is called as a result of the close being done
 *  (e.g. iofunc_close_ocb_default causes it to be called).  We register
 *  it through the mount structure.
*/

void
time_ocb_free (Timeocb_t *tocb)
{
    if (optv) {
        printf ("%s:  in time_ocb_free \n", progname );
    }

    /*
     *  if we actually allocated a buffer (ie:  if the
     *  client called "read", as opposed to just open/close),
     *  return the memory associated with the buffer.
    */

    if (tocb -> buffer) {
        free (tocb -> buffer);
    }

    free (tocb);
}

/*
 *  io_read
 *
 *  At this point, the client has called their library "read"
 *  function, and expects zero or more bytes.
 *  We are getting the format which we are handling for
 *  this request via the "tocb -> ocb . attr -> format" parameter.
*/

int
io_read (resmgr_context_t *ctp, io_read_t *msg, Timeocb_t *tocb)
{
    int     nleft;
    int     onbytes;
    int     status;

    if (optv) {
        printf ("%s:  in io_read, offset is %lld, nbytes %d\n",
                progname, tocb -> ocb . offset, msg -> i.nbytes);
    }

    if ((status = iofunc_read_verify(ctp, msg, &tocb->ocb, NULL)) != EOK)
        return (status);

    // No special xtypes
    if ((msg->i.xtype & _IO_XTYPE_MASK) != _IO_XTYPE_NONE) {
        return(ENOSYS);
    }

    /*
     *  the first time in, get the time and set up
     *  the size
    */

    if (tocb -> buffer == NULL) {
        /* format the output based on the format string for the device currently being used */
        tocb -> buffer = format_time (tocb -> ocb.attr -> format, 0);
        tocb -> bufsize = strlen (tocb -> buffer) + 1;
    }

    /*
     *  on all reads (first and subsequent) calculate
     *  how many bytes we can return to the client,
     *  based upon the number of bytes available (nleft)
     *  and the client's buffer size
    */

    nleft = tocb -> bufsize - tocb -> ocb . offset;
    onbytes = min (msg -> i.nbytes, nleft);

    /*
     *  do the MsgReply here.  Why are we replying instead of having
     *  the resmgr API do it?  To show that you can.
    */

    if (onbytes) {
        MsgReply (ctp -> rcvid, onbytes, tocb -> buffer + tocb -> ocb . offset, onbytes);
    } else {
        MsgReply (ctp -> rcvid, 0, NULL, 0);
    }

    /*
     *  advance the offset to reflect the number
     *  of bytes returned to the client.
    */

    tocb -> ocb . offset += onbytes;

    if (msg->i.nbytes > 0)
        tocb->ocb.attr->attr.flags |= IOFUNC_ATTR_ATIME;

    /*
     *  return _RESMGR_NOREPLY because we've done the
     *  MsgReply ourselves...
    */

    return (_RESMGR_NOREPLY);
}

/*
 *  io_write
 *
 *  At this point, the client has called their library "write"
 *  function.  Writing is not defined for /dev/time, so we just
 *  swallow any bytes that they may have written, just like
 *  /dev/null.  An alternate approach is to return an error at
 *  open time if we detect that the device has been opened for
 *  writing.
*/

int
io_write (resmgr_context_t *ctp, io_write_t *msg, Timeocb_t *tocb)
{
    int status;

    if (optv) {
        printf ("%s:  in io_write\n", progname);
    }

    if ((status = iofunc_write_verify(ctp, msg, &tocb->ocb, NULL)) != EOK)
        return (status);

    // No special xtypes
    if ((msg->i.xtype & _IO_XTYPE_MASK) != _IO_XTYPE_NONE) {
        return(ENOSYS);
    }

    _IO_SET_WRITE_NBYTES (ctp, msg -> i.nbytes); // indicate how many we wrote

    if (msg->i.nbytes > 0)
        tocb->ocb.attr->attr.flags |= IOFUNC_ATTR_MTIME | IOFUNC_ATTR_CTIME;

    return (_RESMGR_NPARTS (0));
}

/*
 *  format_time()
 *
 * Format a time based on the correct device and time offset
 * value.
 *
 *  We assume that the malloc always works.
*/

char *
format_time (char *format, int time_offset)
{
    char    *ptr;
    time_t  now;

    ptr = malloc (64);
    time (&now);
    now += time_offset;
    strftime (ptr, 64, format, localtime (&now));
    return (ptr);
}


/*
 *  options
 *
 *  This routine handles the command line options.
 *  For our /dev/time family, we support:
 *      -v      verbose operation
*/

void
options (int argc, char **argv)
{
    int     opt;

    optv = 0;

    while ((opt = getopt (argc, argv, "v")) != -1) {
       switch (opt) {
       case 'v':
           optv = 1;
           break;
       }
    }
}

   
   
   
   
   
   
   
   
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358
  • 359
  • 360
  • 361
  • 362
  • 363
  • 364
  • 365
  • 366
  • 367
  • 368
  • 369
  • 370
  • 371
  • 372
  • 373
  • 374
  • 375
  • 376
  • 377
  • 378
  • 379
  • 380
  • 381
  • 382
  • 383
  • 384
  • 385
  • 386
  • 387
  • 388
  • 389
  • 390
  • 391
  • 392
  • 393
  • 394
  • 395
  • 396
  • 397
  • 398
  • 399
  • 400
  • 401
  • 402
  • 403
  • 404
  • 405
  • 406
  • 407
  • 408
  • 409
  • 410
  • 411
  • 412
  • 413
  • 414
  • 415
  • 416
  • 417
  • 418
  • 419
  • 420
  • 421
  • 422
  • 423
  • 424
  • 425
  • 426
  • 427
  • 428
  • 429
  • 430
  • 431
  • 432
  • 433
  • 434
  • 435
  • 436
  • 437
  • 438
  • 439
            
                

你可能感兴趣的:(qnx学习)