⬆️ ⬇️

Device Attributes, or ioctl must die

In the process of working on Phantom OS, which is not a place for Unix at all, I nevertheless wanted to make a Unix-compatible subsystem in it. Not exactly POSIX, but something close enough. Partly out of curiosity, partly for convenience, partly as another migration path. (Well, in general, it was interesting how difficult it was to write a simple Unix "out of my head.") As goal number 1, the task was to launch quake 1 for Unix, which was achieved.



In the process, of course, open / close / r / w / ioctl appeared, and it appeared that the latter was indecent, shamefully outdated. As an exercise for brain drowning, I implemented (in addition to the usual ioctl) some alternative API that would allow managing the properties of devices in a more flexible and user-friendly way. This API, of course, has its obvious disadvantages, and, in general, this article is RFC, aka request For Comments.



So, user-level API:

')

// returns name of property with sequential number nProperty, or error errno_t listproperties( int fd, int nProperty, char *buf, int buflen ); errno_t getproperty( int fd, const char *pName, char *buf, int buflen ); errno_t setproperty( int fd, const char *pName, const char *pValue ); 




Rules:



  1. No defaine with numbers, only names.
  2. No binary data, only strings




This is not very efficient, but I would like to assume that setting / reading properties is a rare process, and therefore it makes little sense to rest on its speed, and the context switching itself when calling is a lot.



You can somewhat optimize the interface, for example, like this:



 // returns name of property with sequential number nProperty, or error errno_t listproperties( int fd, int nProperty, char *buf, int buflen ); // returns property id by name errno_t property_by_name( int fd, int *nProperty, const char *name ); errno_t getproperty( int fd, int nProperty, char *buf, int buflen ); errno_t setproperty( int fd, int nProperty, const char *pValue ); // fast lane errno_t getproperty_i32( int fd, int nProperty, int32_t *data ); errno_t setproperty_i32( int fd, int nProperty, int32_t data ); 




This schema for a single property is no slower than an ioctl.



How good it is: you can make a common command (eg mode) that controls the parameters of any driver without knowing anything about it - mode / dev / myCrazyDriver will display a list of properties, and mode / dev / myCrazyDriver name val will set the name property to val.



The implementation inside the driver (for which, of course, there is a corresponding uncomplicated infrastructure in the kernel) is also simple:



 static property_t proplist[] = { { pt_int32, "leds", 0, &leds, 0, (void *)set_leds, 0, 0 }, }; 




This line describes a property that is of type int32, lies in the variable leds, and if it has changed, then it is necessary to call the function set_leds.



In reality, apart from pt_int32, only pt_mstring was born - malloced strings, which is also quite convenient.



In general, it must be said, the pace of development of the classic Unix API is somewhat surprising to me - there is a feeling that no one is seriously concerned with it, although it seems that certain systematization will not harm him.



I have a few more additions to the traditional POSIX, which, to me, a Unixoid with 30 years of experience, seems simply obvious. There will be time - I will publish.



Links to the implementation (skin and bones, but still):







It seems obvious, but I will mention that the mechanism, in principle, can be used for any entities, not only for devices.

Source: https://habr.com/ru/post/282415/



All Articles