Browse code

Getting stacksize values that do not conflict with openblas threads

With the introduction of the USE_TLS option in openblas 0.3.4, threads created by packages loading openblas libraries are affected by a glibc bug described here:

https://sourceware.org/bugzilla/show_bug.cgi?id=11787

The ongoing discussion in openblas:

https://github.com/xianyi/OpenBLAS/issues/1936

Example workarounds used by other projects that inspired this one:

https://github.com/rust-lang/rust/issues/6233
https://github.com/rust-lang/rust/pull/11885
https://bugs.openjdk.java.net/browse/JDK-8225498

Francisco D. MorĂ³n-Duran authored on 29/07/2019 14:02:51
Showing 4 changed files

... ...
@@ -54,6 +54,16 @@ struct loop_data{
54 54
   int start_row;
55 55
   int end_row;
56 56
 };
57
+
58
+#ifdef __linux__
59
+#include <features.h>
60
+#ifdef __GLIBC__
61
+#ifdef __GLIBC_PREREQ && __GLIBC_PREREQ(2, 15)
62
+#define INFER_MIN_STACKSIZE 1
63
+#endif
64
+#endif
65
+#endif
66
+
57 67
 #endif
58 68
 
59 69
 
... ...
@@ -108,11 +118,17 @@ SEXP R_subColSummarize_avg_log(SEXP RMatrix, SEXP R_rowIndexList){
108 118
   double chunk_size_d, chunk_tot_d;
109 119
   char *nthreads;
110 120
   pthread_attr_t attr;
121
+  /* Initialize thread attribute */
122
+  pthread_attr_init(&attr);
111 123
   pthread_t *threads;
112 124
   struct loop_data *args;
113 125
   void *status;
114 126
 #ifdef PTHREAD_STACK_MIN
115
-  size_t stacksize = PTHREAD_STACK_MIN + 0x4000;
127
+#ifdef INFER_MIN_STACKSIZE
128
+  size_t stacksize = __pthread_get_minstack(&attr) + sysconf(_SC_PAGE_SIZE);
129
+#else
130
+  size_t stacksize = PTHREAD_STACK_MIN + sysconf(_SC_PAGE_SIZE);
131
+#endif
116 132
 #else
117 133
   size_t stacksize = 0x8000;
118 134
 #endif
... ...
@@ -136,8 +152,7 @@ SEXP R_subColSummarize_avg_log(SEXP RMatrix, SEXP R_rowIndexList){
136 152
   }
137 153
   threads = (pthread_t *) Calloc(num_threads, pthread_t);
138 154
 
139
-  /* Initialize and set thread detached attribute */
140
-  pthread_attr_init(&attr);
155
+  /* Set thread detached attribute */
141 156
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
142 157
   pthread_attr_setstacksize (&attr, stacksize);
143 158
   /* this code works out how many threads to use and allocates ranges of subColumns to each thread */
... ...
@@ -276,11 +291,17 @@ SEXP R_subColSummarize_log_avg(SEXP RMatrix, SEXP R_rowIndexList){
276 291
   double chunk_size_d, chunk_tot_d;
277 292
   char *nthreads;
278 293
   pthread_attr_t attr;
294
+  /* Initialize thread attribute */
295
+  pthread_attr_init(&attr);
279 296
   pthread_t *threads;
280 297
   struct loop_data *args;
281 298
   void *status; 
282 299
 #ifdef PTHREAD_STACK_MIN
283
-  size_t stacksize = PTHREAD_STACK_MIN + 0x4000;
300
+#ifdef INFER_MIN_STACKSIZE
301
+  size_t stacksize = __pthread_get_minstack(&attr) + sysconf(_SC_PAGE_SIZE);
302
+#else
303
+  size_t stacksize = PTHREAD_STACK_MIN + sysconf(_SC_PAGE_SIZE);
304
+#endif
284 305
 #else
285 306
   size_t stacksize = 0x8000;
286 307
 #endif
... ...
@@ -304,8 +325,7 @@ SEXP R_subColSummarize_log_avg(SEXP RMatrix, SEXP R_rowIndexList){
304 325
   }
305 326
   threads = (pthread_t *) Calloc(num_threads, pthread_t);
306 327
 
307
-  /* Initialize and set thread detached attribute */
308
-  pthread_attr_init(&attr);
328
+  /* Set thread detached attribute */
309 329
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
310 330
   pthread_attr_setstacksize (&attr, stacksize);
311 331
   
... ...
@@ -447,11 +467,17 @@ SEXP R_subColSummarize_avg(SEXP RMatrix, SEXP R_rowIndexList){
447 467
   double chunk_size_d, chunk_tot_d;
448 468
   char *nthreads;
449 469
   pthread_attr_t attr;
470
+  /* Initialize thread attribute */
471
+  pthread_attr_init(&attr);
450 472
   pthread_t *threads;
451 473
   struct loop_data *args;
452 474
   void *status; 
453 475
 #ifdef PTHREAD_STACK_MIN
454
-  size_t stacksize = PTHREAD_STACK_MIN + 0x4000;
476
+#ifdef INFER_MIN_STACKSIZE
477
+  size_t stacksize = __pthread_get_minstack(&attr) + sysconf(_SC_PAGE_SIZE);
478
+#else
479
+  size_t stacksize = PTHREAD_STACK_MIN + sysconf(_SC_PAGE_SIZE);
480
+#endif
455 481
 #else
456 482
   size_t stacksize = 0x8000;
457 483
 #endif
... ...
@@ -475,8 +501,7 @@ SEXP R_subColSummarize_avg(SEXP RMatrix, SEXP R_rowIndexList){
475 501
   }
476 502
   threads = (pthread_t *) Calloc(num_threads, pthread_t);
477 503
 
478
-  /* Initialize and set thread detached attribute */
479
-  pthread_attr_init(&attr);
504
+  /* Set thread detached attribute */
480 505
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
481 506
   pthread_attr_setstacksize (&attr, stacksize);
482 507
   
... ...
@@ -619,11 +644,17 @@ SEXP R_subColSummarize_biweight_log(SEXP RMatrix, SEXP R_rowIndexList){
619 644
   double chunk_size_d, chunk_tot_d;
620 645
   char *nthreads;
621 646
   pthread_attr_t attr;
647
+  /* Initialize thread attribute */
648
+  pthread_attr_init(&attr);
622 649
   pthread_t *threads;
623 650
   struct loop_data *args;
624 651
   void *status;
625 652
 #ifdef PTHREAD_STACK_MIN
626
-  size_t stacksize = PTHREAD_STACK_MIN + 0x4000;
653
+#ifdef INFER_MIN_STACKSIZE
654
+  size_t stacksize = __pthread_get_minstack(&attr) + sysconf(_SC_PAGE_SIZE);
655
+#else
656
+  size_t stacksize = PTHREAD_STACK_MIN + sysconf(_SC_PAGE_SIZE);
657
+#endif
627 658
 #else
628 659
   size_t stacksize = 0x8000;
629 660
 #endif
... ...
@@ -648,8 +679,7 @@ SEXP R_subColSummarize_biweight_log(SEXP RMatrix, SEXP R_rowIndexList){
648 679
   }
649 680
   threads = (pthread_t *) Calloc(num_threads, pthread_t);
650 681
 
651
-  /* Initialize and set thread detached attribute */
652
-  pthread_attr_init(&attr);
682
+  /* Set thread detached attribute */
653 683
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
654 684
   pthread_attr_setstacksize (&attr, stacksize);
655 685
   /* this code works out how many threads to use and allocates ranges of subColumns to each thread */
... ...
@@ -790,11 +820,17 @@ SEXP R_subColSummarize_biweight(SEXP RMatrix, SEXP R_rowIndexList){
790 820
   double chunk_size_d, chunk_tot_d;
791 821
   char *nthreads;
792 822
   pthread_attr_t attr;
823
+  /* Initialize thread attribute */
824
+  pthread_attr_init(&attr);
793 825
   pthread_t *threads;
794 826
   struct loop_data *args;
795 827
   void *status;
796 828
 #ifdef PTHREAD_STACK_MIN
797
-  size_t stacksize = PTHREAD_STACK_MIN + 0x4000;
829
+#ifdef INFER_MIN_STACKSIZE
830
+  size_t stacksize = __pthread_get_minstack(&attr) + sysconf(_SC_PAGE_SIZE);
831
+#else
832
+  size_t stacksize = PTHREAD_STACK_MIN + sysconf(_SC_PAGE_SIZE);
833
+#endif
798 834
 #else
799 835
   size_t stacksize = 0x8000;
800 836
 #endif
... ...
@@ -818,8 +854,7 @@ SEXP R_subColSummarize_biweight(SEXP RMatrix, SEXP R_rowIndexList){
818 854
   }
819 855
   threads = (pthread_t *) Calloc(num_threads, pthread_t);
820 856
 
821
-  /* Initialize and set thread detached attribute */
822
-  pthread_attr_init(&attr);
857
+  /* Set thread detached attribute */
823 858
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
824 859
   pthread_attr_setstacksize (&attr, stacksize);
825 860
   
... ...
@@ -962,11 +997,17 @@ SEXP R_subColSummarize_median_log(SEXP RMatrix, SEXP R_rowIndexList){
962 997
   double chunk_size_d, chunk_tot_d;
963 998
   char *nthreads;
964 999
   pthread_attr_t attr;
1000
+  /* Initialize thread attribute */
1001
+  pthread_attr_init(&attr);
965 1002
   pthread_t *threads;
966 1003
   struct loop_data *args;
967 1004
   void *status;
968 1005
 #ifdef PTHREAD_STACK_MIN
969
-  size_t stacksize = PTHREAD_STACK_MIN + 0x4000;
1006
+#ifdef INFER_MIN_STACKSIZE
1007
+  size_t stacksize = __pthread_get_minstack(&attr) + sysconf(_SC_PAGE_SIZE);
1008
+#else
1009
+  size_t stacksize = PTHREAD_STACK_MIN + sysconf(_SC_PAGE_SIZE);
1010
+#endif
970 1011
 #else
971 1012
   size_t stacksize = 0x8000;
972 1013
 #endif
... ...
@@ -990,8 +1031,7 @@ SEXP R_subColSummarize_median_log(SEXP RMatrix, SEXP R_rowIndexList){
990 1031
   }
991 1032
   threads = (pthread_t *) Calloc(num_threads, pthread_t);
992 1033
 
993
-  /* Initialize and set thread detached attribute */
994
-  pthread_attr_init(&attr);
1034
+  /* Set thread detached attribute */
995 1035
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
996 1036
   pthread_attr_setstacksize (&attr, stacksize);
997 1037
   
... ...
@@ -1132,11 +1172,17 @@ SEXP R_subColSummarize_log_median(SEXP RMatrix, SEXP R_rowIndexList){
1132 1172
   double chunk_size_d, chunk_tot_d;
1133 1173
   char *nthreads;
1134 1174
   pthread_attr_t attr;
1175
+  /* Initialize thread attribute */
1176
+  pthread_attr_init(&attr);
1135 1177
   pthread_t *threads;
1136 1178
   struct loop_data *args;
1137 1179
   void *status; 
1138 1180
 #ifdef PTHREAD_STACK_MIN
1139
-  size_t stacksize = PTHREAD_STACK_MIN + 0x4000;
1181
+#ifdef INFER_MIN_STACKSIZE
1182
+  size_t stacksize = __pthread_get_minstack(&attr) + sysconf(_SC_PAGE_SIZE);
1183
+#else
1184
+  size_t stacksize = PTHREAD_STACK_MIN + sysconf(_SC_PAGE_SIZE);
1185
+#endif
1140 1186
 #else
1141 1187
   size_t stacksize = 0x8000;
1142 1188
 #endif
... ...
@@ -1160,8 +1206,7 @@ SEXP R_subColSummarize_log_median(SEXP RMatrix, SEXP R_rowIndexList){
1160 1206
   }
1161 1207
   threads = (pthread_t *) Calloc(num_threads, pthread_t);
1162 1208
 
1163
-  /* Initialize and set thread detached attribute */
1164
-  pthread_attr_init(&attr);
1209
+  /* Set thread detached attribute */
1165 1210
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
1166 1211
   pthread_attr_setstacksize (&attr, stacksize);
1167 1212
   
... ...
@@ -1301,11 +1346,17 @@ SEXP R_subColSummarize_median(SEXP RMatrix, SEXP R_rowIndexList){
1301 1346
   double chunk_size_d, chunk_tot_d;
1302 1347
   char *nthreads;
1303 1348
   pthread_attr_t attr;
1349
+  /* Initialize thread attribute */
1350
+  pthread_attr_init(&attr);
1304 1351
   pthread_t *threads;
1305 1352
   struct loop_data *args;
1306 1353
   void *status; 
1307 1354
 #ifdef PTHREAD_STACK_MIN
1308
-  size_t stacksize = PTHREAD_STACK_MIN + 0x4000;
1355
+#ifdef INFER_MIN_STACKSIZE
1356
+  size_t stacksize = __pthread_get_minstack(&attr) + sysconf(_SC_PAGE_SIZE);
1357
+#else
1358
+  size_t stacksize = PTHREAD_STACK_MIN + sysconf(_SC_PAGE_SIZE);
1359
+#endif
1309 1360
 #else
1310 1361
   size_t stacksize = 0x8000;
1311 1362
 #endif
... ...
@@ -1329,8 +1380,7 @@ SEXP R_subColSummarize_median(SEXP RMatrix, SEXP R_rowIndexList){
1329 1380
   }
1330 1381
   threads = (pthread_t *) Calloc(num_threads, pthread_t);
1331 1382
 
1332
-  /* Initialize and set thread detached attribute */
1333
-  pthread_attr_init(&attr);
1383
+  /* Set thread detached attribute */
1334 1384
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
1335 1385
   pthread_attr_setstacksize (&attr, stacksize);
1336 1386
   
... ...
@@ -1475,11 +1525,17 @@ SEXP R_subColSummarize_medianpolish_log(SEXP RMatrix, SEXP R_rowIndexList){
1475 1525
   double chunk_size_d, chunk_tot_d;
1476 1526
   char *nthreads;
1477 1527
   pthread_attr_t attr;
1528
+  /* Initialize thread attribute */
1529
+  pthread_attr_init(&attr);
1478 1530
   pthread_t *threads;
1479 1531
   struct loop_data *args;
1480 1532
   void *status; 
1481 1533
 #ifdef PTHREAD_STACK_MIN
1482
-  size_t stacksize = PTHREAD_STACK_MIN + 0x4000;
1534
+#ifdef INFER_MIN_STACKSIZE
1535
+  size_t stacksize = __pthread_get_minstack(&attr) + sysconf(_SC_PAGE_SIZE);
1536
+#else
1537
+  size_t stacksize = PTHREAD_STACK_MIN + sysconf(_SC_PAGE_SIZE);
1538
+#endif
1483 1539
 #else
1484 1540
   size_t stacksize = 0x8000;
1485 1541
 #endif
... ...
@@ -1507,8 +1563,7 @@ SEXP R_subColSummarize_medianpolish_log(SEXP RMatrix, SEXP R_rowIndexList){
1507 1563
   }
1508 1564
   threads = (pthread_t *) Calloc(num_threads, pthread_t);
1509 1565
 
1510
-  /* Initialize and set thread detached attribute */
1511
-  pthread_attr_init(&attr);
1566
+  /* Set thread detached attribute */
1512 1567
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
1513 1568
   pthread_attr_setstacksize (&attr, stacksize);
1514 1569
   
... ...
@@ -1650,11 +1705,17 @@ SEXP R_subColSummarize_medianpolish(SEXP RMatrix, SEXP R_rowIndexList){
1650 1705
   double chunk_size_d, chunk_tot_d;
1651 1706
   char *nthreads;
1652 1707
   pthread_attr_t attr;
1708
+  /* Initialize thread attribute */
1709
+  pthread_attr_init(&attr);
1653 1710
   pthread_t *threads;
1654 1711
   struct loop_data *args;
1655 1712
   void *status; 
1656 1713
 #ifdef PTHREAD_STACK_MIN
1657
-  size_t stacksize = PTHREAD_STACK_MIN + 0x4000;
1714
+#ifdef INFER_MIN_STACKSIZE
1715
+  size_t stacksize = __pthread_get_minstack(&attr) + sysconf(_SC_PAGE_SIZE);
1716
+#else
1717
+  size_t stacksize = PTHREAD_STACK_MIN + sysconf(_SC_PAGE_SIZE);
1718
+#endif
1658 1719
 #else
1659 1720
   size_t stacksize = 0x8000;
1660 1721
 #endif
... ...
@@ -1678,8 +1739,7 @@ SEXP R_subColSummarize_medianpolish(SEXP RMatrix, SEXP R_rowIndexList){
1678 1739
   }
1679 1740
   threads = (pthread_t *) Calloc(num_threads, pthread_t);
1680 1741
 
1681
-  /* Initialize and set thread detached attribute */
1682
-  pthread_attr_init(&attr);
1742
+  /* Set thread detached attribute */
1683 1743
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
1684 1744
   pthread_attr_setstacksize (&attr, stacksize);
1685 1745
   
... ...
@@ -51,6 +51,16 @@ struct loop_data{
51 51
   int start_row;
52 52
   int end_row;
53 53
 };
54
+
55
+#ifdef __linux__
56
+#include <features.h>
57
+#ifdef __GLIBC__
58
+#ifdef __GLIBC_PREREQ && __GLIBC_PREREQ(2, 15)
59
+#define INFER_MIN_STACKSIZE 1
60
+#endif
61
+#endif
62
+#endif
63
+
54 64
 #endif
55 65
 
56 66
 
... ...
@@ -165,11 +175,17 @@ SEXP R_sub_rcModelSummarize_medianpolish(SEXP RMatrix, SEXP R_rowIndexList){
165 175
   double chunk_size_d, chunk_tot_d;
166 176
   char *nthreads;
167 177
   pthread_attr_t attr;
178
+  /* Initialize thread attribute */
179
+  pthread_attr_init(&attr);
168 180
   pthread_t *threads;
169 181
   struct loop_data *args;
170 182
   void *status; 
171 183
 #ifdef PTHREAD_STACK_MIN
172
-  size_t stacksize = PTHREAD_STACK_MIN + 0x4000;
184
+#ifdef INFER_MIN_STACKSIZE
185
+  size_t stacksize = __pthread_get_minstack(&attr) + sysconf(_SC_PAGE_SIZE);
186
+#else
187
+  size_t stacksize = PTHREAD_STACK_MIN + sysconf(_SC_PAGE_SIZE);
188
+#endif
173 189
 #else
174 190
   size_t stacksize = 0x8000;
175 191
 #endif
... ...
@@ -211,8 +227,7 @@ SEXP R_sub_rcModelSummarize_medianpolish(SEXP RMatrix, SEXP R_rowIndexList){
211 227
   }
212 228
   threads = (pthread_t *) Calloc(num_threads, pthread_t);
213 229
 
214
-  /* Initialize and set thread detached attribute */
215
-  pthread_attr_init(&attr);
230
+  /* Set thread detached attribute */
216 231
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
217 232
   pthread_attr_setstacksize (&attr, stacksize);
218 233
   
... ...
@@ -480,11 +495,17 @@ SEXP R_sub_rcModelSummarize_plm(SEXP RMatrix, SEXP R_rowIndexList, SEXP PsiCode,
480 495
   double chunk_size_d, chunk_tot_d;
481 496
   char *nthreads;
482 497
   pthread_attr_t attr;
498
+  /* Initialize thread attribute */
499
+  pthread_attr_init(&attr);
483 500
   pthread_t *threads;
484 501
   struct loop_data *args;
485 502
   void *status; 
486 503
 #ifdef PTHREAD_STACK_MIN
487
-  size_t stacksize = PTHREAD_STACK_MIN + 0x4000;
504
+#ifdef INFER_MIN_STACKSIZE
505
+  size_t stacksize = __pthread_get_minstack(&attr) + sysconf(_SC_PAGE_SIZE);
506
+#else
507
+  size_t stacksize = PTHREAD_STACK_MIN + sysconf(_SC_PAGE_SIZE);
508
+#endif
488 509
 #else
489 510
   size_t stacksize = 0x8000;
490 511
 #endif
... ...
@@ -532,8 +553,7 @@ SEXP R_sub_rcModelSummarize_plm(SEXP RMatrix, SEXP R_rowIndexList, SEXP PsiCode,
532 553
   }
533 554
   threads = (pthread_t *) Calloc(num_threads, pthread_t);
534 555
 
535
-  /* Initialize and set thread detached attribute */
536
-  pthread_attr_init(&attr);
556
+  /* Set thread detached attribute */
537 557
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
538 558
   pthread_attr_setstacksize (&attr, stacksize);
539 559
   
... ...
@@ -110,6 +110,16 @@ struct loop_data{
110 110
   int start_col;
111 111
   int end_col;
112 112
 };
113
+
114
+#ifdef __linux__
115
+#include <features.h>
116
+#ifdef __GLIBC__
117
+#ifdef __GLIBC_PREREQ && __GLIBC_PREREQ(2, 15)
118
+#define INFER_MIN_STACKSIZE 1
119
+#endif
120
+#endif
121
+#endif
122
+
113 123
 #endif
114 124
 
115 125
 /*****************************************************************************************************
... ...
@@ -486,11 +496,17 @@ int qnorm_c_l(double *data, size_t rows, size_t cols){
486 496
   double chunk_size_d, chunk_tot_d;
487 497
   char *nthreads;
488 498
   pthread_attr_t attr;
499
+  /* Initialize thread attribute */
500
+  pthread_attr_init(&attr);
489 501
   pthread_t *threads;
490 502
   struct loop_data *args;
491 503
   void *status;
492 504
 #ifdef PTHREAD_STACK_MIN
493
-  size_t stacksize = PTHREAD_STACK_MIN + 0x4000;
505
+#ifdef INFER_MIN_STACKSIZE
506
+  size_t stacksize = __pthread_get_minstack(&attr);
507
+#else
508
+  size_t stacksize = PTHREAD_STACK_MIN + sysconf(_SC_PAGE_SIZE);
509
+#endif
494 510
 #else
495 511
   size_t stacksize = 0x8000;
496 512
 #endif
... ...
@@ -510,8 +526,7 @@ int qnorm_c_l(double *data, size_t rows, size_t cols){
510 526
   }
511 527
   threads = (pthread_t *) Calloc(num_threads, pthread_t);
512 528
 
513
-  /* Initialize and set thread detached attribute */
514
-  pthread_attr_init(&attr);
529
+  /* Set thread detached attribute */
515 530
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
516 531
   pthread_attr_setstacksize (&attr, stacksize);
517 532
   
... ...
@@ -1597,11 +1612,17 @@ int qnorm_c_using_target_l(double *data, size_t rows, size_t cols, double *targe
1597 1612
   double chunk_size_d, chunk_tot_d;
1598 1613
   char *nthreads;
1599 1614
   pthread_attr_t attr;
1615
+  /* Initialize thread attribute */
1616
+  pthread_attr_init(&attr);
1600 1617
   pthread_t *threads;
1601 1618
   struct loop_data *args;
1602 1619
   void *status;
1603 1620
 #ifdef PTHREAD_STACK_MIN
1604
-  size_t stacksize = PTHREAD_STACK_MIN + 0x4000;
1621
+#ifdef INFER_MIN_STACKSIZE
1622
+  size_t stacksize = __pthread_get_minstack(&attr) + sysconf(_SC_PAGE_SIZE);
1623
+#else
1624
+  size_t stacksize = PTHREAD_STACK_MIN + sysconf(_SC_PAGE_SIZE);
1625
+#endif
1605 1626
 #else
1606 1627
   size_t stacksize = 0x8000;
1607 1628
 #endif
... ...
@@ -1631,9 +1652,7 @@ int qnorm_c_using_target_l(double *data, size_t rows, size_t cols, double *targe
1631 1652
   }
1632 1653
   threads = (pthread_t *) Calloc(num_threads, pthread_t);
1633 1654
 
1634
-  /* Initialize and set thread detached attribute */
1635
-
1636
-  pthread_attr_init(&attr);
1655
+  /* Set thread detached attribute */
1637 1656
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
1638 1657
   pthread_attr_setstacksize (&attr, stacksize);
1639 1658
 
... ...
@@ -1890,11 +1909,17 @@ int qnorm_c_determine_target_l(double *data, size_t rows, size_t cols, double *t
1890 1909
   double chunk_size_d, chunk_tot_d;
1891 1910
   char *nthreads;
1892 1911
   pthread_attr_t attr;
1912
+  /* Initialize thread attribute */
1913
+  pthread_attr_init(&attr);
1893 1914
   pthread_t *threads;
1894 1915
   struct loop_data *args;
1895 1916
   void *status;
1896 1917
 #ifdef PTHREAD_STACK_MIN
1897
-  size_t stacksize = PTHREAD_STACK_MIN + 0x4000;
1918
+#ifdef INFER_MIN_STACKSIZE
1919
+  size_t stacksize = __pthread_get_minstack(&attr) + sysconf(_SC_PAGE_SIZE);
1920
+#else
1921
+  size_t stacksize = PTHREAD_STACK_MIN + sysconf(_SC_PAGE_SIZE);
1922
+#endif
1898 1923
 #else
1899 1924
   size_t stacksize = 0x8000;
1900 1925
 #endif
... ...
@@ -1910,8 +1935,7 @@ int qnorm_c_determine_target_l(double *data, size_t rows, size_t cols, double *t
1910 1935
   }
1911 1936
   threads = (pthread_t *) Calloc(num_threads, pthread_t);
1912 1937
 
1913
-  /* Initialize and set thread detached attribute */
1914
-  pthread_attr_init(&attr);
1938
+  /* Set thread detached attribute */
1915 1939
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
1916 1940
   pthread_attr_setstacksize (&attr, stacksize);
1917 1941
 
... ...
@@ -2484,11 +2508,17 @@ int qnorm_c_determine_target_via_subset_l(double *data, size_t rows, size_t cols
2484 2508
   double chunk_size_d, chunk_tot_d;
2485 2509
   char *nthreads;
2486 2510
   pthread_attr_t attr;
2511
+  /* Initialize thread attribute */
2512
+  pthread_attr_init(&attr);
2487 2513
   pthread_t *threads;
2488 2514
   struct loop_data *args;
2489 2515
   void *status;
2490 2516
 #ifdef PTHREAD_STACK_MIN
2491
-  size_t stacksize = PTHREAD_STACK_MIN + 0x4000;
2517
+#ifdef INFER_MIN_STACKSIZE
2518
+  size_t stacksize = __pthread_get_minstack(&attr) + sysconf(_SC_PAGE_SIZE);
2519
+#else
2520
+  size_t stacksize = PTHREAD_STACK_MIN + sysconf(_SC_PAGE_SIZE);
2521
+#endif
2492 2522
 #else
2493 2523
   size_t stacksize = 0x8000;
2494 2524
 #endif
... ...
@@ -2504,8 +2534,7 @@ int qnorm_c_determine_target_via_subset_l(double *data, size_t rows, size_t cols
2504 2534
   }
2505 2535
   threads = (pthread_t *) Calloc(num_threads, pthread_t);
2506 2536
 
2507
-  /* Initialize and set thread detached attribute */
2508
-  pthread_attr_init(&attr);
2537
+  /* Set thread detached attribute */
2509 2538
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
2510 2539
   pthread_attr_setstacksize (&attr, stacksize);
2511 2540
 
... ...
@@ -2988,11 +3017,17 @@ int qnorm_c_using_target_via_subset_l(double *data, size_t rows, size_t cols, in
2988 3017
   double chunk_size_d, chunk_tot_d;
2989 3018
   char *nthreads;
2990 3019
   pthread_attr_t attr;
3020
+  /* Initialize thread attribute */
3021
+  pthread_attr_init(&attr);
2991 3022
   pthread_t *threads;
2992 3023
   struct loop_data *args;
2993 3024
   void *status;
2994 3025
 #ifdef PTHREAD_STACK_MIN
2995
-  size_t stacksize = PTHREAD_STACK_MIN + 0x4000;
3026
+#ifdef INFER_MIN_STACKSIZE
3027
+  size_t stacksize = __pthread_get_minstack(&attr) + sysconf(_SC_PAGE_SIZE);
3028
+#else
3029
+  size_t stacksize = PTHREAD_STACK_MIN + sysconf(_SC_PAGE_SIZE);
3030
+#endif
2996 3031
 #else
2997 3032
   size_t stacksize = 0x8000;
2998 3033
 #endif
... ...
@@ -3022,9 +3057,7 @@ int qnorm_c_using_target_via_subset_l(double *data, size_t rows, size_t cols, in
3022 3057
   }
3023 3058
   threads = (pthread_t *) Calloc(num_threads, pthread_t);
3024 3059
 
3025
-  /* Initialize and set thread detached attribute */
3026
-
3027
-  pthread_attr_init(&attr);
3060
+  /* Set thread detached attribute */
3028 3061
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
3029 3062
   pthread_attr_setstacksize (&attr, stacksize);
3030 3063
 
... ...
@@ -58,6 +58,16 @@ struct loop_data{
58 58
   size_t start_col;
59 59
   size_t end_col;
60 60
 };
61
+
62
+#ifdef __linux__
63
+#include <features.h>
64
+#ifdef __GLIBC__
65
+#ifdef __GLIBC_PREREQ &&  __GLIBC_PREREQ(2, 15)
66
+#define INFER_MIN_STACKSIZE 1
67
+#endif
68
+#endif
69
+#endif
70
+
61 71
 #endif
62 72
 
63 73
 
... ...
@@ -347,11 +357,17 @@ void rma_bg_correct(double *PM, size_t rows, size_t cols){
347 357
   double chunk_size_d, chunk_tot_d;
348 358
   char *nthreads;
349 359
   pthread_attr_t attr;
360
+  /* Initialize thread attribute */
361
+  pthread_attr_init(&attr);
350 362
   pthread_t *threads;
351 363
   struct loop_data *args;
352 364
   void *status;
353 365
 #ifdef PTHREAD_STACK_MIN
354
-  size_t stacksize = PTHREAD_STACK_MIN + 0x4000;
366
+#ifdef INFER_MIN_STACKSIZE
367
+  size_t stacksize = __pthread_get_minstack(&attr) + sysconf(_SC_PAGE_SIZE);
368
+#else
369
+  size_t stacksize = PTHREAD_STACK_MIN + sysconf(_SC_PAGE_SIZE);
370
+#endif
355 371
 #else
356 372
   size_t stacksize = 0x8000;
357 373
 #endif
... ...
@@ -369,8 +385,7 @@ void rma_bg_correct(double *PM, size_t rows, size_t cols){
369 385
   }
370 386
   threads = (pthread_t *) Calloc(num_threads, pthread_t);
371 387
 
372
-  /* Initialize and set thread detached attribute */
373
-  pthread_attr_init(&attr);
388
+  /* Set thread detached attribute */
374 389
   pthread_attr_setdetachstate(&attr, PTHREAD_CREATE_JOINABLE);
375 390
   pthread_attr_setstacksize (&attr, stacksize);
376 391
   /* this code works out how many threads to use and allocates ranges of columns to each thread */