Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
att
GitHub Repository: att/ast
Path: blob/master/src/lib/libast/aso/aso.c
1811 views
1
/***********************************************************************
2
* *
3
* This software is part of the ast package *
4
* Copyright (c) 1985-2012 AT&T Intellectual Property *
5
* and is licensed under the *
6
* Eclipse Public License, Version 1.0 *
7
* by AT&T Intellectual Property *
8
* *
9
* A copy of the License is available at *
10
* http://www.eclipse.org/org/documents/epl-v10.html *
11
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12
* *
13
* Information and Software Systems Research *
14
* AT&T Research *
15
* Florham Park NJ *
16
* *
17
* Glenn Fowler <[email protected]> *
18
* David Korn <[email protected]> *
19
* Phong Vo <[email protected]> *
20
* *
21
***********************************************************************/
22
#pragma prototyped
23
24
#include "asohdr.h"
25
#include "FEATURE/aso"
26
27
#if defined(_UWIN) && defined(_BLD_ast)
28
29
NoN(aso)
30
31
#else
32
33
/*
34
* ast atomic scalar operations
35
* AT&T Research
36
*
37
* cas { 8 16 32 [64] } subset snarfed from the work by
38
* Adam Edgar and Kiem-Phong Vo 2010-10-10
39
*
40
* lock methods and emulations by
41
* Glenn Fowler 2011-11-11
42
*
43
* hopefully stable by 2012-12-12
44
*/
45
46
#if !_PACKAGE_ast
47
48
#if _UWIN
49
50
extern ssize_t sfsprintf(char*, size_t, const char*, ...);
51
52
#else
53
54
#include <stdio.h>
55
56
#define sfsprintf snprintf
57
58
#endif
59
60
#endif
61
62
#if defined(_aso_casptr) && (defined(_aso_cas32) || defined(_aso_cas64))
63
#define ASO_METHOD (&_aso_meth_intrinsic)
64
#define ASO_LOCKF 0
65
#else
66
#define ASO_METHOD (&_aso_meth_signal)
67
#define ASO_LOCKF _aso_lock_signal
68
#endif
69
70
typedef union
71
{
72
uint8_t c[2];
73
uint16_t i;
74
} U16_8_t;
75
76
typedef union
77
{
78
uint8_t c[4];
79
uint32_t i;
80
} U32_8_t;
81
82
typedef union
83
{
84
uint16_t c[2];
85
uint32_t i;
86
} U32_16_t;
87
88
#ifdef _ast_int8_t
89
90
typedef union
91
{
92
uint8_t c[8];
93
uint64_t i;
94
} U64_8_t;
95
96
typedef union
97
{
98
uint16_t c[4];
99
uint64_t i;
100
} U64_16_t;
101
102
typedef union
103
{
104
uint32_t c[2];
105
uint64_t i;
106
} U64_32_t;
107
108
#endif
109
110
typedef struct State_s
111
{
112
Asometh_t* meth;
113
Asolock_f lockf;
114
Asoerror_f errorf;
115
uintmax_t hung;
116
unsigned int hung2;
117
void* data;
118
pid_t pid;
119
} State_t;
120
121
static unsigned int _aso_data_signal;
122
123
static ssize_t
124
_aso_lock_signal(void* data, ssize_t k, void volatile* p)
125
{
126
if (k >= 0)
127
{
128
_aso_data_signal--;
129
return 0;
130
}
131
while (_aso_data_signal++)
132
_aso_data_signal--;
133
return 1;
134
}
135
136
static Asometh_t _aso_meth_signal = { "signal", ASO_SIGNAL, 0, _aso_lock_signal };
137
extern Asometh_t _aso_meth_semaphore;
138
extern Asometh_t _aso_meth_fcntl;
139
static Asometh_t _aso_meth_intrinsic = { "intrinsic", ASO_INTRINSIC|ASO_PROCESS|ASO_THREAD|ASO_SIGNAL, 0, 0 };
140
141
static Asometh_t* method[] =
142
{
143
&_aso_meth_signal,
144
#if defined(_ast_int8_t) && defined(_aso_cas64) || !defined(_ast_int8_t) && defined(_aso_cas32)
145
&_aso_meth_intrinsic,
146
#endif
147
#if _aso_semaphore
148
&_aso_meth_semaphore,
149
#endif
150
#if _aso_fcntl
151
&_aso_meth_fcntl,
152
#endif
153
};
154
155
static State_t state =
156
{
157
ASO_METHOD, ASO_LOCKF
158
};
159
160
static int
161
asoerror(int type, const char* format, const char* a, const char* b, long n)
162
{
163
char buf[128];
164
165
if (b)
166
sfsprintf(buf, sizeof(buf), format, a, b, n);
167
else if (a)
168
sfsprintf(buf, sizeof(buf), format, a, n);
169
else
170
sfsprintf(buf, sizeof(buf), format, n);
171
return state.errorf(type, buf);
172
}
173
174
/*
175
* if type!=0 return lock method for type with name details
176
* else if name!=0 return lock method matching <name>[,<details>]
177
* else return the current lock method
178
* 0 returned on error
179
*
180
* the user visible asometh() calls this function
181
* it allows, e.g., for -ltaso to provide an asometh() intercept
182
* that prepends its ASO_THREAD methods ahead of the _asometh() methods
183
*/
184
185
Asometh_t*
186
_asometh(int type, void* data)
187
{
188
size_t n;
189
int i;
190
char* e;
191
Asometh_t* meth;
192
char* name;
193
194
if (type == ASO_NEXT)
195
{
196
if (!(meth = (Asometh_t*)data))
197
return method[0];
198
for (i = 0; i < elementsof(method) - 1; i++)
199
if (meth == method[i])
200
return method[i+1];
201
return 0;
202
}
203
if (type)
204
{
205
for (i = 0; i < elementsof(method); i++)
206
if (method[i]->type & type)
207
{
208
method[i]->details = (char*)data;
209
return method[i];
210
}
211
return 0;
212
}
213
if (!(name = (char*)data))
214
return state.meth;
215
n = (e = strchr(name, ',')) ? (e - name) : strlen(name);
216
for (i = 0; i < elementsof(method); i++)
217
if (strncmp(name, method[i]->name, n) == 0)
218
{
219
if (e)
220
method[i]->details = e + 1;
221
return method[i];
222
}
223
return 0;
224
}
225
226
/*
227
* clean up lock method on exit
228
*/
229
230
static void
231
asoexit(void)
232
{
233
if (state.meth && state.meth->initf && state.data && state.pid == getpid())
234
{
235
state.lockf = ASO_METHOD->lockf;
236
state.meth->initf(state.data, 0);
237
state.data = 0;
238
}
239
}
240
241
/*
242
* initialize lock method
243
*/
244
245
int
246
asoinit(const char* details, Asometh_t* meth, Asodisc_t* disc)
247
{
248
void* data;
249
250
if (disc)
251
{
252
state.errorf = disc->errorf;
253
state.hung2 = disc->hung;
254
state.hung = 1;
255
state.hung <<= state.hung2;
256
state.hung--;
257
}
258
if (!meth)
259
return state.pid != 0;
260
if (!meth->lockf && !(meth->type & ASO_INTRINSIC))
261
{
262
if (state.errorf)
263
asoerror(ASO_EMETHOD, "%s method has no lock function", meth->name, 0, 0);
264
return -1;
265
}
266
state.lockf = ASO_METHOD->lockf;
267
if (state.meth && state.meth->initf && state.data)
268
{
269
state.meth->initf(state.data, 0);
270
state.data = 0;
271
}
272
if (!meth->initf)
273
data = 0;
274
else if (!(data = meth->initf(0, details ? details : meth->details)))
275
{
276
state.meth = ASO_METHOD;
277
if (state.errorf)
278
asoerror(ASO_EMETHOD, "%s method initialization failed -- reverting to the %s method", meth->name, state.meth->name, 0);
279
return -1;
280
}
281
state.meth = meth;
282
state.data = data;
283
state.lockf = meth->lockf;
284
if (!state.pid)
285
{
286
state.pid = getpid();
287
atexit(asoexit);
288
}
289
return 0;
290
}
291
292
/*
293
* loop check for hung spin locks
294
* and periodic relinquishing of the processor
295
*/
296
297
int
298
asoloop(uintmax_t rep)
299
{
300
if (state.hung && !(rep & state.hung) && state.errorf)
301
return asoerror(ASO_EHUNG, "spin lock possibly hung after 2^%u attempts", 0, 0, state.hung2);
302
return (rep & ASO_RELAX) ? 0 : asorelax(1);
303
}
304
305
/*
306
* error checking state.lockf() call
307
*/
308
309
static ssize_t
310
lock(void* data, ssize_t k, void volatile* p)
311
{
312
ssize_t r;
313
314
if ((r = state.lockf(data, k, p)) < 0 && state.errorf)
315
asoerror(ASO_EMETHOD, "%s method lock failed", state.meth->name, 0, 0);
316
return r;
317
}
318
319
/*
320
* sync and return "current" value
321
*/
322
323
uint8_t
324
asoget8(uint8_t volatile* p)
325
{
326
int o;
327
328
do
329
{
330
o = *p;
331
} while (asocas8(p, o, o) != o);
332
return o;
333
}
334
335
uint16_t
336
asoget16(uint16_t volatile* p)
337
{
338
int o;
339
340
do
341
{
342
o = *p;
343
} while (asocas16(p, o, o) != o);
344
return o;
345
}
346
347
uint32_t
348
asoget32(uint32_t volatile* p)
349
{
350
uint32_t o;
351
352
do
353
{
354
o = *p;
355
} while (asocas32(p, o, o) != o);
356
return o;
357
}
358
359
#ifdef _ast_int8_t
360
361
uint64_t
362
asoget64(uint64_t volatile* p)
363
{
364
uint64_t o;
365
366
do
367
{
368
o = *p;
369
} while (asocas64(p, o, o) != o);
370
return o;
371
}
372
373
#endif
374
375
void*
376
asogetptr(void volatile* p)
377
{
378
void* o;
379
380
do
381
{
382
o = *(void* volatile*)p;
383
} while (asocasptr(p, o, o) != o);
384
return o;
385
}
386
387
/*
388
* increment and return old value
389
*/
390
391
uint8_t
392
asoinc8(uint8_t volatile* p)
393
{
394
ssize_t k;
395
int o;
396
397
#if defined(_aso_inc8)
398
if (!state.lockf)
399
return _aso_inc8(p);
400
#else
401
if (!state.lockf)
402
{
403
do
404
{
405
o = *p;
406
} while (asocas8(p, o, o + 1) != o);
407
return o;
408
}
409
#endif
410
k = lock(state.data, 0, p);
411
o = (*p)++;
412
lock(state.data, k, p);
413
return o;
414
}
415
416
uint16_t
417
asoinc16(uint16_t volatile* p)
418
{
419
ssize_t k;
420
int o;
421
422
#if defined(_aso_inc16)
423
if (!state.lockf)
424
return _aso_inc16(p);
425
#else
426
if (!state.lockf)
427
{
428
do
429
{
430
o = *p;
431
} while (asocas16(p, o, o + 1) != o);
432
return o;
433
}
434
#endif
435
k = lock(state.data, 0, p);
436
o = (*p)++;
437
lock(state.data, k, p);
438
return o;
439
}
440
441
uint32_t
442
asoinc32(uint32_t volatile* p)
443
{
444
ssize_t k;
445
int o;
446
447
#if defined(_aso_inc32)
448
if (!state.lockf)
449
return _aso_inc32(p);
450
#else
451
if (!state.lockf)
452
{
453
do
454
{
455
o = *p;
456
} while (asocas32(p, o, o + 1) != o);
457
return o;
458
}
459
#endif
460
k = lock(state.data, 0, p);
461
o = (*p)++;
462
lock(state.data, k, p);
463
return o;
464
}
465
466
#ifdef _ast_int8_t
467
468
uint64_t
469
asoinc64(uint64_t volatile* p)
470
{
471
ssize_t k;
472
uint64_t o;
473
474
#if defined(_aso_inc64)
475
if (!state.lockf)
476
return _aso_inc64(p);
477
#else
478
if (!state.lockf)
479
{
480
do
481
{
482
o = *p;
483
} while (asocas64(p, o, o + 1) != o);
484
return o;
485
}
486
#endif
487
k = lock(state.data, 0, p);
488
o = (*p)++;
489
lock(state.data, k, p);
490
return o;
491
}
492
493
#endif
494
495
/*
496
* decrement and return old value
497
*/
498
499
uint8_t
500
asodec8(uint8_t volatile* p)
501
{
502
ssize_t k;
503
int o;
504
505
#if defined(_aso_dec8)
506
if (!state.lockf)
507
return _aso_dec8(p);
508
#else
509
if (!state.lockf)
510
{
511
do
512
{
513
o = *p;
514
} while (asocas8(p, o, o - 1) != o);
515
return o;
516
}
517
#endif
518
k = lock(state.data, 0, p);
519
o = (*p)--;
520
lock(state.data, k, p);
521
return o;
522
}
523
524
uint16_t
525
asodec16(uint16_t volatile* p)
526
{
527
ssize_t k;
528
int o;
529
530
#if defined(_aso_dec16)
531
if (!state.lockf)
532
return _aso_dec16(p);
533
#else
534
if (!state.lockf)
535
{
536
do
537
{
538
o = *p;
539
} while (asocas16(p, o, o - 1) != o);
540
return o;
541
}
542
#endif
543
k = lock(state.data, 0, p);
544
o = (*p)--;
545
lock(state.data, k, p);
546
return o;
547
}
548
549
uint32_t
550
asodec32(uint32_t volatile* p)
551
{
552
ssize_t k;
553
int o;
554
555
#if defined(_aso_dec32)
556
if (!state.lockf)
557
return _aso_dec32(p);
558
#else
559
if (!state.lockf)
560
{
561
do
562
{
563
o = *p;
564
} while (asocas32(p, o, o - 1) != o);
565
return o;
566
}
567
#endif
568
k = lock(state.data, 0, p);
569
o = (*p)--;
570
lock(state.data, k, p);
571
return o;
572
}
573
574
#ifdef _ast_int8_t
575
576
uint64_t
577
asodec64(uint64_t volatile* p)
578
{
579
ssize_t k;
580
uint64_t o;
581
582
#if defined(_aso_dec64)
583
if (!state.lockf)
584
return _aso_dec64(p);
585
#else
586
if (!state.lockf)
587
{
588
do
589
{
590
o = *p;
591
} while (asocas64(p, o, o - 1) != o);
592
return o;
593
}
594
#endif
595
k = lock(state.data, 0, p);
596
o = (*p)--;
597
lock(state.data, k, p);
598
return o;
599
}
600
601
#endif
602
603
/*
604
* { 8 16 32 [64] } compare with old, swap with new if same, and return old value
605
*/
606
607
uint8_t
608
asocas8(uint8_t volatile* p, int o, int n)
609
{
610
ssize_t k;
611
612
#if defined(_aso_cas8)
613
if (!state.lockf)
614
return _aso_cas8(p, o, n);
615
#elif defined(_aso_cas16)
616
if (!state.lockf)
617
{
618
U16_8_t u;
619
U16_8_t v;
620
U16_8_t* a;
621
int s;
622
int i;
623
624
s = (int)(integralof(p) & (sizeof(u.i) - 1));
625
a = (U16_8_t*)((char*)0 + (integralof(p) & ~(sizeof(u.i) - 1)));
626
for (;;)
627
{
628
u.i = a->i;
629
u.c[s] = o;
630
v.i = u.i;
631
v.c[s] = n;
632
if (_aso_cas16(&a->i, u.i, v.i) == u.i)
633
break;
634
for (i = 0;; i++)
635
if (i >= elementsof(u.c))
636
return a->c[s];
637
else if (i != s && u.c[i] != a->c[i])
638
break;
639
}
640
return o;
641
}
642
#elif defined(_aso_cas32)
643
if (!state.lockf)
644
{
645
U32_8_t u;
646
U32_8_t v;
647
U32_8_t* a;
648
int s;
649
int i;
650
651
s = (int)(integralof(p) & (sizeof(u.i) - 1));
652
a = (U32_8_t*)((char*)0 + (integralof(p) & ~(sizeof(u.i) - 1)));
653
for (;;)
654
{
655
u.i = a->i;
656
u.c[s] = o;
657
v.i = u.i;
658
v.c[s] = n;
659
if (_aso_cas32(&a->i, u.i, v.i) == u.i)
660
break;
661
for (i = 0;; i++)
662
if (i >= elementsof(u.c))
663
return a->c[s];
664
else if (i != s && u.c[i] != a->c[i])
665
break;
666
}
667
return o;
668
}
669
#elif defined(_aso_cas64)
670
if (!state.lockf)
671
{
672
U64_8_t u;
673
U64_8_t v;
674
U64_8_t* a;
675
int s;
676
int i;
677
678
s = (int)(integralof(p) & (sizeof(u.i) - 1));
679
a = (U64_8_t*)((char*)0 + (integralof(p) & ~(sizeof(u.i) - 1)));
680
for (;;)
681
{
682
u.i = a->i;
683
u.c[s] = o;
684
v.i = u.i;
685
v.c[s] = n;
686
if (_aso_cas64(&a->i, u.i, v.i) == u.i)
687
break;
688
for (i = 0;; i++)
689
if (i >= elementsof(u.c))
690
return a->c[s];
691
else if (i != s && u.c[i] != a->c[i])
692
break;
693
}
694
return o;
695
}
696
#endif
697
k = lock(state.data, 0, p);
698
if (*p == o)
699
*p = n;
700
else
701
o = *p;
702
lock(state.data, k, p);
703
return o;
704
}
705
706
uint16_t
707
asocas16(uint16_t volatile* p, uint16_t o, uint16_t n)
708
{
709
ssize_t k;
710
711
#if defined(_aso_cas16)
712
if (!state.lockf)
713
return _aso_cas16(p, o, n);
714
#elif defined(_aso_cas32)
715
if (!state.lockf)
716
{
717
U32_16_t u;
718
U32_16_t v;
719
U32_16_t* a;
720
int s;
721
int i;
722
723
s = (int)(integralof(p) & (sizeof(u.i) - 1)) / 2;
724
a = (U32_16_t*)((char*)0 + (integralof(p) & ~(sizeof(u.i) - 1)));
725
for (;;)
726
{
727
u.i = a->i;
728
u.c[s] = o;
729
v.i = u.i;
730
v.c[s] = n;
731
if (_aso_cas32(&a->i, u.i, v.i) == u.i)
732
break;
733
for (i = 0;; i++)
734
if (i >= elementsof(u.c))
735
return a->c[s];
736
else if (i != s && u.c[i] != a->c[i])
737
break;
738
}
739
return o;
740
}
741
#elif defined(_aso_cas64)
742
if (!state.lockf)
743
{
744
U64_16_t u;
745
U64_16_t v;
746
U64_16_t* a;
747
int s;
748
int i;
749
750
s = (int)(integralof(p) & (sizeof(u.i) - 1)) / 2;
751
a = (U64_16_t*)((char*)0 + (integralof(p) & ~(sizeof(u.i) - 1)));
752
for (;;)
753
{
754
u.i = a->i;
755
u.c[s] = o;
756
v.i = u.i;
757
v.c[s] = n;
758
if (_aso_cas64(&a->i, u.i, v.i) == u.i)
759
break;
760
for (i = 0;; i++)
761
if (i >= elementsof(u.c))
762
return a->c[s];
763
else if (i != s && u.c[i] != a->c[i])
764
break;
765
}
766
return o;
767
}
768
#endif
769
k = lock(state.data, 0, p);
770
if (*p == o)
771
*p = n;
772
else
773
o = *p;
774
lock(state.data, k, p);
775
return o;
776
}
777
778
uint32_t
779
asocas32(uint32_t volatile* p, uint32_t o, uint32_t n)
780
{
781
ssize_t k;
782
783
#if defined(_aso_cas32)
784
if (!state.lockf)
785
return _aso_cas32(p, o, n);
786
#elif defined(_aso_cas64)
787
if (!state.lockf)
788
{
789
U64_32_t u;
790
U64_32_t v;
791
U64_32_t* a;
792
int s;
793
int i;
794
795
s = (int)(integralof(p) & (sizeof(u.i) - 1)) / 4;
796
a = (U64_32_t*)((char*)0 + (integralof(p) & ~(sizeof(u.i) - 1)));
797
for (;;)
798
{
799
u.i = a->i;
800
u.c[s] = o;
801
v.i = u.i;
802
v.c[s] = n;
803
if (_aso_cas64(&a->i, u.i, v.i) == u.i)
804
break;
805
for (i = 0;; i++)
806
if (i >= elementsof(u.c))
807
return a->c[s];
808
else if (i != s && u.c[i] != a->c[i])
809
break;
810
}
811
return o;
812
}
813
#endif
814
k = lock(state.data, 0, p);
815
if (*p == o)
816
*p = n;
817
else
818
o = *p;
819
lock(state.data, k, p);
820
return o;
821
}
822
823
#ifdef _ast_int8_t
824
825
uint64_t
826
asocas64(uint64_t volatile* p, uint64_t o, uint64_t n)
827
{
828
ssize_t k;
829
830
#if defined(_aso_cas64)
831
if (!state.lockf)
832
return _aso_cas64(p, o, n);
833
#endif
834
k = lock(state.data, 0, p);
835
if (*p == o)
836
*p = n;
837
else
838
o = *p;
839
lock(state.data, k, p);
840
return o;
841
}
842
843
#endif
844
845
/*
846
* compare with old, swap with new if same, and return old value
847
*/
848
849
void*
850
asocasptr(void volatile* p, void* o, void* n)
851
{
852
ssize_t k;
853
854
#if defined(_aso_casptr)
855
if (!state.lockf)
856
return _aso_casptr((void**)p, o, n);
857
#endif
858
k = lock(state.data, 0, p);
859
if (*(void* volatile*)p == o)
860
*(void* volatile*)p = n;
861
else
862
o = *(void* volatile*)p;
863
lock(state.data, k, p);
864
return o;
865
}
866
867
#endif
868
869