Skip to content

Commit b47cb64

Browse files
committed
move mutable flags to bitflags for ct_flags_mut field
1 parent 8aa0680 commit b47cb64

File tree

1 file changed

+28
-27
lines changed

1 file changed

+28
-27
lines changed

src/c/_cffi_backend.c

Lines changed: 28 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -285,6 +285,15 @@ static int PyWeakref_GetRef(PyObject *ref, PyObject **pobj)
285285
CT_PRIMITIVE_FLOAT | \
286286
CT_PRIMITIVE_COMPLEX)
287287

288+
/* flags that are mutable at runtime, stored separately in ct_flags_mut to avoid
289+
races with ct_flags
290+
291+
these are read and set without using atomic operations because a lock is held
292+
while mutating ct_flags_mut
293+
*/
294+
#define CT_CUSTOM_FIELD_POS 0x00000001
295+
#define CT_WITH_VAR_ARRAY 0x00000002 /* with open-ended array, anywhere */
296+
#define CT_WITH_PACKED_CHANGE 0x00000004
288297

289298
typedef struct _ctypedescr {
290299
PyObject_VAR_HEAD
@@ -309,13 +318,11 @@ typedef struct _ctypedescr {
309318
or alignment of primitive and struct types;
310319
always -1 for pointers */
311320
int ct_flags; /* Immutable CT_xxx flags */
321+
int ct_flags_mut; /* Mutable CT_xxx flags */
312322
uint8_t ct_under_construction;
313323
uint8_t ct_under_realization;
314324
uint8_t ct_lazy_field_list;
315325
uint8_t ct_unrealized_struct_or_union;
316-
uint8_t ct_custom_field_pos;
317-
uint8_t ct_with_packed_change;
318-
uint8_t ct_with_var_array; /* with open-ended array, anywhere */
319326
int ct_name_position; /* index in ct_name of where to put a var name */
320327
char ct_name[1]; /* string, e.g. "int *" for pointers to ints */
321328
} CTypeDescrObject;
@@ -474,9 +481,7 @@ ctypedescr_new(int name_size)
474481
ct->ct_under_realization = 0;
475482
ct->ct_under_construction = 0;
476483
ct->ct_unrealized_struct_or_union = 0;
477-
ct->ct_custom_field_pos = 0;
478-
ct->ct_with_packed_change = 0;
479-
ct->ct_with_var_array = 0;
484+
ct->ct_flags_mut = 0;
480485
PyObject_GC_Track(ct);
481486
return ct;
482487
}
@@ -1513,8 +1518,7 @@ convert_vfield_from_object(char *data, CFieldObject *cf, PyObject *value,
15131518
if (optvarsize == NULL) {
15141519
return convert_field_from_object(data, cf, value);
15151520
}
1516-
else if (cffi_check_flag(cf->cf_type->ct_with_var_array) != 0 &&
1517-
!CData_Check(value)) {
1521+
else if ((cf->cf_type->ct_flags_mut & CT_WITH_VAR_ARRAY) && !CData_Check(value)) {
15181522
Py_ssize_t subsize = cf->cf_type->ct_size;
15191523
if (convert_struct_from_object(NULL, cf->cf_type, value, &subsize) < 0)
15201524
return -1;
@@ -2268,7 +2272,7 @@ static Py_ssize_t _cdata_var_byte_size(CDataObject *cd)
22682272
if (cd->c_type->ct_flags & CT_IS_PTR_TO_OWNED) {
22692273
cd = (CDataObject *)((CDataObject_own_structptr *)cd)->structobj;
22702274
}
2271-
if (cffi_check_flag(cd->c_type->ct_with_var_array)) {
2275+
if (cd->c_type->ct_flags_mut & CT_WITH_VAR_ARRAY) {
22722276
return ((CDataObject_own_length *)cd)->length;
22732277
}
22742278
return -1;
@@ -3858,7 +3862,7 @@ convert_struct_to_owning_object(char *data, CTypeDescrObject *ct)
38583862
"return type is an opaque structure or union");
38593863
return NULL;
38603864
}
3861-
if (cffi_check_flag(ct->ct_with_var_array)) {
3865+
if (ct->ct_flags_mut & CT_WITH_VAR_ARRAY) {
38623866
PyErr_SetString(PyExc_TypeError,
38633867
"return type is a struct/union with a varsize array member");
38643868
return NULL;
@@ -3967,7 +3971,7 @@ static PyObject *direct_newp(CTypeDescrObject *ct, PyObject *init,
39673971
datasize *= 2; /* forcefully add another character: a null */
39683972

39693973
if (ctitem->ct_flags & (CT_STRUCT | CT_UNION)) {
3970-
if (cffi_check_flag(ctitem->ct_with_var_array)) {
3974+
if (ctitem->ct_flags_mut & CT_WITH_VAR_ARRAY) {
39713975
assert(ct->ct_flags & CT_IS_PTR_TO_OWNED);
39723976
dataoffset = offsetof(CDataObject_own_length, alignment);
39733977

@@ -5282,7 +5286,7 @@ static int detect_custom_layout(CTypeDescrObject *ct, int sflags,
52825286
ct->ct_name);
52835287
return -1;
52845288
}
5285-
cffi_set_flag(ct->ct_custom_field_pos, 1);
5289+
ct->ct_flags_mut |= CT_CUSTOM_FIELD_POS;
52865290
}
52875291
return 0;
52885292
}
@@ -5320,8 +5324,8 @@ static PyObject *b_complete_struct_or_union_lock_held(CTypeDescrObject *ct,
53205324
"first arg must be a non-initialized struct or union ctype");
53215325
goto finally;
53225326
}
5323-
cffi_set_flag(ct->ct_custom_field_pos, 0);
5324-
cffi_set_flag(ct->ct_with_packed_change, 0);
5327+
ct->ct_flags_mut &= ~CT_CUSTOM_FIELD_POS;
5328+
ct->ct_flags_mut &= ~CT_WITH_PACKED_CHANGE;
53255329

53265330
alignment = 1;
53275331
byteoffset = 0; /* the real value is 'byteoffset+bitoffset*8', which */
@@ -5359,7 +5363,7 @@ static PyObject *b_complete_struct_or_union_lock_held(CTypeDescrObject *ct,
53595363
if (cffi_get_size(ftype) < 0) {
53605364
if ((ftype->ct_flags & CT_ARRAY) && fbitsize < 0
53615365
&& (i == nb_fields - 1 || foffset != -1)) {
5362-
cffi_set_flag(ct->ct_with_var_array, 1);
5366+
ct->ct_flags_mut |= CT_WITH_VAR_ARRAY;
53635367
}
53645368
else {
53655369
PyErr_Format(PyExc_TypeError,
@@ -5373,11 +5377,11 @@ static PyObject *b_complete_struct_or_union_lock_held(CTypeDescrObject *ct,
53735377
/* GCC (or maybe C99) accepts var-sized struct fields that are not
53745378
the last field of a larger struct. That's why there is no
53755379
check here for "last field": we propagate the flag
5376-
ct_with_var_array to any struct that contains either an open-
5380+
CT_WITH_VAR_ARRAY to any struct that contains either an open-
53775381
ended array or another struct that recursively contains an
53785382
open-ended array. */
5379-
if (cffi_check_flag(ftype->ct_with_var_array)) {
5380-
cffi_set_flag(ct->ct_with_var_array, 1);
5383+
if (ftype->ct_flags_mut & CT_WITH_VAR_ARRAY) {
5384+
ct->ct_flags_mut |= CT_WITH_VAR_ARRAY;
53815385
}
53825386
}
53835387

@@ -5426,12 +5430,12 @@ static PyObject *b_complete_struct_or_union_lock_held(CTypeDescrObject *ct,
54265430
byteoffset = (byteoffset + falign-1) & ~(falign-1);
54275431

54285432
if (byteoffsetorg != byteoffset) {
5429-
cffi_set_flag(ct->ct_with_packed_change, 1);
5433+
ct->ct_flags_mut |= CT_WITH_PACKED_CHANGE;
54305434
}
54315435

54325436
if (foffset >= 0) {
54335437
/* a forced field position: ignore the offset just computed,
5434-
except to know if we must set ct_custom_field_pos */
5438+
except to know if we must set CT_CUSTOM_FIELD_POS */
54355439
if (detect_custom_layout(ct, sflags, byteoffset, foffset,
54365440
"wrong offset for field '",
54375441
PyText_AS_UTF8(fname), "'") < 0)
@@ -5459,7 +5463,7 @@ static PyObject *b_complete_struct_or_union_lock_held(CTypeDescrObject *ct,
54595463
previous = &(*previous)->cf_next;
54605464
}
54615465
/* always forbid such structures from being passed by value */
5462-
cffi_set_flag(ct->ct_custom_field_pos, 1);
5466+
ct->ct_flags_mut |= CT_CUSTOM_FIELD_POS;
54635467
}
54645468
else {
54655469
*previous = _add_field(interned_fields, fname, ftype,
@@ -5760,15 +5764,15 @@ static ffi_type *fb_fill_type(struct funcbuilder_s *fb, CTypeDescrObject *ct,
57605764
differently: e.g. on x86-64, "b" ends up in register "rsi" in
57615765
the first case and "rdi" in the second case.
57625766
5763-
Another reason for ct_custom_field_pos would be anonymous
5767+
Another reason for CT_CUSTOM_FIELD_POS would be anonymous
57645768
nested structures: we lost the information about having it
57655769
here, so better safe (and forbid it) than sorry (and maybe
57665770
crash). Note: it seems we only get in this case with
57675771
ffi.verify().
57685772
*/
57695773
if (force_lazy_struct(ct) < 0)
57705774
return NULL;
5771-
if (cffi_check_flag(ct->ct_custom_field_pos)) {
5775+
if (ct->ct_flags_mut & CT_CUSTOM_FIELD_POS) {
57725776
/* these NotImplementedErrors may be caught and ignored until
57735777
a real call is made to a function of this type */
57745778
return fb_unsupported(ct, place,
@@ -5778,7 +5782,7 @@ static ffi_type *fb_fill_type(struct funcbuilder_s *fb, CTypeDescrObject *ct,
57785782
}
57795783
/* Another reason: __attribute__((packed)) is not supported by libffi.
57805784
*/
5781-
if (cffi_check_flag(ct->ct_with_packed_change)) {
5785+
if (ct->ct_flags_mut & CT_WITH_PACKED_CHANGE) {
57825786
return fb_unsupported(ct, place,
57835787
"It is a 'packed' structure, with a different layout than "
57845788
"expected by libffi");
@@ -6760,9 +6764,6 @@ static PyObject *b_new_enum_type(PyObject *self, PyObject *args)
67606764
td->ct_length = basetd->ct_length; /* alignment */
67616765
td->ct_extra = basetd->ct_extra; /* ffi type */
67626766
td->ct_flags = basetd->ct_flags | CT_IS_ENUM;
6763-
td->ct_custom_field_pos = cffi_check_flag(basetd->ct_custom_field_pos);
6764-
td->ct_with_packed_change = cffi_check_flag(basetd->ct_with_packed_change);
6765-
td->ct_with_var_array = cffi_check_flag(basetd->ct_with_var_array);
67666767
td->ct_name_position = name_size - 1;
67676768
return (PyObject *)td;
67686769

0 commit comments

Comments
 (0)