I am searching for a good way to document the following enum / typedef design in a shared library that I have inherited. There are many instances of the following pattern:
enum {
VAL1,
VAL2,
VAL3
};
typedef u_int16_t val_t;
int16_t myfunc(val_t foo);
This obviously causes problems with Doxygen's link generation.
Unfortunately, I cannot change this to the proper typedef enum { ... } val_t; structure that one would expect as this library runs on many different embedded systems ranging from native 16bit to 64bit. Per the C standard, an enum is guaranteed to be large enough to hold an int. Thus, changing these into proper typedefs promotes their size from sizeof(u_int16_t) (2 bytes) to sizeof(int) (usually 4 bytes but not always). Chaos ensues from storage size differences; nevermind the coordinated release nightmare required to rebuild all dependent software.
Given the above, is there any good way to mark in the comment block preceding the enum that the below is actually an alias for the typedef?
Failing that, I am looking for a solution that will concisely allow me to find these values from an arbitrary function signature. I can name the enums to something arbitrary (ex. val_enum_t) so I have considered both #see mentions as well as direct links using the # prefix. In both cases, another layer of links is generated.
My ideal solution would consist of the following:
One click from function signature to enumerated value list. Failing one click, as few clicks as possible.
Inline documentation for the enums using //!<.
If a direct association cannot be made, a single comment block to describe functionality which can be displayed on both the typedef as well as the enum itself.
Related
I would like to develop a device-driver on linux(written in C) and a user-space library wrapping all functions provided by my device-driver (also written in C). Just to make it more clear, my library wil provide the following methods:
int myOpen();
void myClose();
mySetConf(MyconfStruct conf)
etc.
The function will use the file associated to my device-driver, in particular:
myOpen will call the open() of my device-driver
myClose will call the close() of my device-driver
mySetConf will call the ioctl() of my device driver and pass the myConfStruct as a parameter to configure the device-driver using ioctl().
assume myConfStruct is a simple structure containing something like this:
typedef struct {
uint16_t var1;
uint8_t var2;
} myConfStruct;
I would like the myConfStruct to be a structure shared between both my user-application (library) and my kernel-driver using a single header.
Are there any best-practice while doing this?
I would like to have the structure defined into only one file, having it defined in multiple files seems to be quite error-prone if i plan on changing it in the future, but I understood that I should not include <linux/types.h> inside my user files and I shouldn't use <stdint.h> inside my device-driver.
So another question is also, how can I define the interface between a module and the user-application so that who is implementing the application is not forced to include any linux header?
What you are creating is a character device. The kernel documentation includes a specific section, the Linux driver implementer's guide, you should also read. Specifically, the ioctl based interfaces section, which also describes some of the considerations necessary (regarding alignment and 64-bit fields).
As to header files, see KernelHeaders article at kernelnewbies.org.
I would like to have the structure defined into only one file, having it defined in multiple files seems to be quite error-prone if i plan on changing it in the future.
No. You do specify the headers in two separate files: one for use in-kernel, and the other for use by userspace.
Kernel-userspace interface should be stable. You should take care to design your data structure so that you can extend it if necessary; preferably by adding some padding reserved for future use and required to be initialized to zero, and/or a version number at the beginning of the structure. Later versions must support all previous versions of the structure as well. Even if it is only a "toy" or "experimental" device driver, it is best to learn to do it right from the get go. This stuff is much, much harder to learn to "add afterwards"; I'm talking from deep experience here.
As a character device, you should also be prepared for the driver to be compiled on other architectures besides the one you are developing on. Even byte order ("endianness") can vary, although all Linux architectures are currently either ILP32 or LP64.
Also remember that there are several hardware architectures, including x86-64, that support both 64-bit and 32-bit userspace. So, even if you believe your driver will ever be used on x86-64, you cannot really assume the userspace is 64-bit (and not 32-bit). Look at existing code to see how it is done right; I recommend using e.g. bootlin's elixir to browse the Linux kernel sources.
Kernel-side header file should use __s8, __u8, __s16, __u16, __s32, __u32, __s64, or __u64. For pointers, use __u64, and u64_to_user_ptr().
Userspace-side header file should use <stdint.h> types (int8_t, uint8_t, int16_t, uint16_t, int32_t, uint32_t, int64_t, uint64_t) and uint64_t for pointers. Use a cast via (uintptr_t) for the conversion, i.e. ptr = (void *)(uintptr_t)u64; and u64 = (uintptr_t)ptr.
Ensure all members are naturally aligned. This means that an N-bit member is preceded by k×N bits of other members, where k is either zero or a positive integer. Thus, if your structure needs an unsigned and a signed 8-bit integer (one for version, one for foo), an 16-bit signed integer (bar), and a 64-bit unsigned integer (baz), considering the version should be first, you'll probably want
struct kernel_side {
__u8 version;
__s8 foo;
__u16 bar;
__u32 padding;
__u64 baz;
};
struct userspace_side {
uint8_t version;
int8_t foo;
uint16_t bar;
uint32_t padding;
uint64_t baz;
};
You can also have character arrays and such, but do note that a single ioctl data block is limited to 8191 bytes or less in length.
If you spend some time designing your interface structures, you'll find that careful design will avoid annoying issues like compat_ support (making them just simple wrappers). Personally, I end up creating a test version with a userspace test program to see what works best, and only then decide on the data structures.
I ran into some weird issues (at compile time) with my embedded C code when I increased the size of the array from size [2] to [27] which contained structured metadata. So it is obvious that this is a nested structured style program and NOT my original work!
I remember in assembly code instructions, there used to be a JMP FAR, JMP NEAR/SHORT.. Is there any such limitations in structures (obviously there is no jump in structures). Could there be a condition that the compiler cannot assign a contiguous memory block for a structure because there is a limit to it and fails during compilation.
SOME CLUE: The fix as i recall was to move the member (array member)from original structure to another nested structure. That's the reason why i deduced that there maybe a limitation.
//STRUCTURES
typedef UINT8 P_Name_t[5];
typedef UINT8 ChipSN_t[3];
typedef struct
{
ChipSN_t ChipSN;
<other members>
} ChipIdent_t;
typedef struct Data_t
{
ChipIdent_t ReadOnlyMemID;
<other members>
} Data_t;
typedef struct
{
P_Name_t NameOfPart;
<other members>
} Log_t;
Data_t Data_Src;
typedef struct
{
P_Name_t NameOfPart;
ChipSN_t ChipSN;
}PartNum_ID_t;
typedef struct
{
PartNum_ID_t PN_ChipID[27];
<other members>;
}
According to standard, there is a limitation; but the limitation is much more than the size you mentioned here. C89 and C99 standard has the limit of 1023 structure members. See below text from the standard.
5.2.4.1 Translation limits
— 1023 members in a single structure or union
So looks like if your code is correct and limited to 1023 structure members the compiler you are using may have the limitation.
There may indeed be a limit to the number of structure elements your compiler can handle for a single structure, but as MCG quoted from the C Standard, this limit must be at least 1023 for compliant compilers and most compilers have higher limits or no practical limits at all.
I suspect the problem is elsewhere:
The Makefile for your project may have incomplete dependencies on the header file with the structure definitions: modules compiled with different definitions will be incompatible and produce undefined behavior. Remove all object files and recompile the project.
Some assembly modules may rely on the original structure layout: changing the definition will only affect the recompiled C modules.
Some library modules or OS system calls may rely on the original layout. Recompiling all libraries or even patching the OS may be required.
Some functions may rely on the original layout and use casts to access some of the structures via another type. Changing the layout may break such code, which is brittle anyway as even changing compilers may produce similar problems.
It is also possible that some of the type be multiply defined in different modules. This is poor and very error prone coding style as changing only one of the definitions will lead to undefined behavior when the object modules are linked together.
if you want to cut to the chase, please skip down to the last two paragraphs. If you're interested in my predicament and the steps I've taken to solve it, continue reading directly below.
I am currently developing portions of a C library as part of my internship. So naturally, there are some parts of code which should not be accessible to the user while others should be. I am basically developing several architecture-optimized random number generators (RNG's)(uniform, Gaussian, and exponential distributed numbers). The latter two RNG's depend on the uniform generator , which is in a different kernel (project). So, in the case that the user wants to use more than one RNG, I want to make sure I'm not duplicating code needlessly since we are constrained with memory (no point in having the same function defined multiple times at different addresses in the code segment).
Now here's where the problem arises. The convention for all other kernels in the library is that we have a two header files and two C files (one each for the natural C implementation and the optimized C version (which may use some intrinsic functions and assembly and/or have some restrictions to make it faster and better for our architecture). This is followed by another C file (a testbench) where our main function is located and it tests both implementations and compares the results. With that said, we cannot really add an additional header file for private or protected items nor can we add a global header file for all these generators.
To combat this restriction, I used extern functions and extern const int's in the C files which depend on the uniform RNG rather than #define's at the top of each C file in order to make the code more portable and easily modified in one place. This worked for the most part.
However, the tricky bit is that we are using an internal type within these kernels (which should not be seen by the user and should not be placed in the header file). Again, for portability, I would like to be able to change the definition of this typedef in one place rather than in multiple places in multiple kernels since the library may be used for another platform later on and for the algorithms to work it is critical that I use 32-bit types.
So basically I'm wondering if there's any way I can make a typedef "protected" in C. That is, I need it to be visible among all C files which need it, but invisible to the user. It can be in one of the header files, but must not be visible to the user who will be including that header file in his/her project, whatever that may be.
============================Edit================================
I should also note that the typedef I am using is an unsigned int. so
typedef unsigned int myType
No structures involved.
============================Super Edit==========================
The use of stdint.h is also forbidden :(
I am expanding on Jens Gustedt’s answer since the OP still has questions.
First, it is unclear why you have separate header files for the two implementations (“natural C” and “optimized C”). If they implement the same API, one header should serve for either.
Jens Gustedt’s recommendation is that you declare a struct foo in the header but define it only in the C source file for the implementation and not in the header. A struct declared in this way is an incomplete type, and source code that can only see the declaration, and not the definition, cannot see what is in the type. It can, however, use pointers to the type.
The declaration of an incomplete struct may be as simple as struct foo. You can also define a type, such as typedef struct foo foo; or typedef struct foo Mytype;, and you can define a type that is a pointer to the struct, such as typedef struct foo *FooPointer;. However, these are merely for convenience. They do not alter the basic notion, that there is a struct foo that API users cannot see into but that they can have pointers to.
Inside the implementation, you would fully define the struct. If you want an unsigned int in the struct, you would use:
struct foo
{
unsigned int x;
};
In general, you define the struct foo to contain whatever data you like.
Since the API user cannot define struct foo, you must provide functions to create and destroy objects of this type as necessary. Thus, you would likely have a function declared as extern struct foo *FooAlloc(some parameters);. The function creates a struct foo object (likely by calling malloc or a related function), initializes it with data from the parameters, and returns a pointer to the object (or NULL if the creation or initialization fails). You would also have a function extern void FooFree(struct foo *p); that frees a struct foo object. You might also have functions to reset, set, or alter the state of a foo object, functions to copy foo objects, and functions to report about foo objects.
Your implementations could also define some global struct foo objects that could be visible (essentially by address only) to API users. As a matter of good design, this should be done only for certain special purposes, such as to provide instances of struct foo objects with special meanings, such as a constant object with a permanent “initial state” for copying.
Your two implementations, the “natural C” and the “optimized C” implementations may have different definitions for the struct foo, provided they are not both used in a program together. (That is, each entire program is compiled with one implementation or the other, not both. If necessary, you could mangle both into a program by using a union, but it is preferable to avoid that.)
This is not a singleton approach.
Just do
typedef struct foo foo;
These are two declarations, a forward declaration of a struct and a type alias with the same name. Forward declared struct can be used to nothing else than to define pointers to them. This should give you enough abstraction and type safety.
In all your interfaces you'd have
extern void proc(foo* a);
and you'd have to provide functions
extern foo* foo_alloc(size_t n);
extern void foo_free(foo* a);
This would bind your users as well as your library to always use the same struct. Thereby the implementation of foo is completely hidden to the API users. You could even one day to decide to use something different than a struct since users should use foo without the struct keyword.
Edit: Just a typedef to some kind of integer wouldn't help you much, because these are only aliases for types. All your types aliased to unsigned could be used interchangeably. One way around this would be to encapsulate them inside a struct. This would make your internal code a bit ugly, but the generated object code should be exactly the same with a good modern compiler.
Let's say that there's an interface specification "X". X calls for XHeader.h to have a struct called X_Fiddle that guarantees the presence of members foo and bar, both of type int. However, implementation-defined members are not prohibited and are in fact encouraged if doing so increases efficiency. I need to write an implementation of X for the company I work for, and realised that having a few members specific to my implementation to store some state would be very convenient, so I wrote the following:
typedef struct X_Fiddle {
int foo; /* Guaranteed by spec */
int bar; /* Guaranteed by spec */
size_t dinky_dingbat; /* IMPLEMENTATION-SPECIFIC, DO NOT USE */
unsigned char *dingbat_data; /* IMPLEMENTATION-SPECIFIC, DO NOT USE */
} X_Fiddle;
Of course, there's nothing to tell the users that dinky_dingbat or dingbat_data should not be used since they are implementation-specific details and may change or disappear at some point in the future. Given that I can't hide the implementation by using something like opaque pointers, what should I do to make such internal members stand out (or other tricks to hide such things)? Are there any commonly used/standard ways of dealing with problems like this? Best I could think of is using a naming convention like leading underscores, but I'm not sure if the leading underscores rules apply to member variables, and I have a feeling that I'm getting mixed up with some C++ specific rules too. I also thought of naming them something like INTERNAL_dinky_dingbat or having a separate struct for internal types contained inside X_Fiddle, but I'd like to keep the extra typing to a minimum so I dislike them somewhat. Or is it perfectly acceptable just to have a plain, ordinary struct as above, where implementation-specific details are spelled out in the comments and documentation, leaving the less experienced and diligent to suffer their self-inflicted wounds when I need to change things around?
Assuming I'm starting from scratch and/or my company/team has no convention for this specific case.
Even if the PIMPL idiom is C++ thing, it has actually be used for longer in plain C as anonymous void pointers.
If you want the structure to have private implementation-specific fields, then create a structure for those private fields, and add a void pointer field to the public structure. Then have an init or create function which allocates this private structure, and makes the void pointer field in the public structure point to that private structure.
The GLib Object System provides an object system with data hiding and inheritance. If you cannot use it in your application, you can at least get some ideas from it.
Is there any alternative to non-ISO gcc specific extension __attribute__ on 64-bit kernels ?
Three types that i've noticed are: function attributes, type attributes and variable attributes.
eg.
i'd like to avoid using __attribute__((__packed__)) for structures passed over the network, even though some gcc based code do use it.
Any suggestions or pointers on how to entirely avoid __attribute__ usage in C systems/kernel code ?
thanks
Saifi.
Any suggestions or pointers on how to entirely avoid attribute usage in C systems/kernel code?
You can build your network packets piece by piece, copying each data element into the correct place in a char* buffer.
Pros: you don't have any alignment issues and it's generally portable, especially if you use the exact-width integer types from <stdint.h>
Cons: it's tedious and potentially error-prone
I'm assuming based on your comments that its your code you want to change, not the whole Linux kernel (etc).
Not sure about function attributes etc but specifically for attribute packed, I have done the following with no issues so far.
Basically instead of relying on the compiler to pack, you could use manual pad fields coupled with compile-time asserts.
struct foo {
u32 field1;
u16 field2;
u16 pad; // manual padding
// continue for other fields that the compiler would automatically pad for you with attribute packed
u32 field3;
};
To check your structure you can use a compile time assert, something like this:
#define CASSERT(cond, name) typedef cassert__##name[cond ? 1 : -1]
CASSERT(offsetof(foo, field1) == 0, field1_wrong);
CASSERT(offsetof(foo, field2) == 4, field2_wrong);
When your assertions are wrong, the build will fail with a helpful error and line number