0001:
0002:
0003:
0004:
0005:
0006:
0007:
0008:
0009:
0010:
0011:
0012:
0013:
0014:
0015:
0016:
0017:
0018:
0019:
0020:
0021:
0022:
0023:
0024:
0025:
0026:
0027:
0028:
0029:
0030:
0031:
0032:
0033:
0034:
0035:
0036:
0037:
0038:
0039:
0040:
0041:
0042:
0043:
0044:
0045:
0046:
0047:
0048:
0049:
0050:
0051:
0052:
0053:
0054:
0055:
0056:
0057:
0058:
0059:
0060:
0061:
0062:
0063:
0064:
0065:
0066:
0067:
0068:
0069:
0070:
0071:
0072:
0073:
0074:
0075:
0076:
0077:
0078:
0079:
0080:
0081:
0082:
0083:
0084:
0085:
0086:
0087:
0088:
0089:
0090:
0091:
0092:
0093:
0094:
0095:
0096:
0097:
0098:
0099:
0100:
0101:
0102:
0103:
0104:
0105:
0106:
0107:
0108:
0109:
0110:
0111:
0112:
0113:
0114:
0115:
0116:
0117:
0118:
0119:
0120:
0121:
0122:
0123:
0124:
0125:
0126:
0127:
0128:
0129:
0130:
0131:
0132:
0133:
0134:
0135:
0136:
0137:
0138:
0139:
0140:
0141:
0142:
0143:
0144:
0145:
0146:
0147:
0148:
0149:
0150:
0151:
0152:
0153:
0154:
0155:
0156:
0157:
0158:
0159:
0160:
0161:
0162:
0163:
0164:
0165:
0166:
0167:
0168:
0169:
0170:
0171:
0172:
0173:
0174:
0175:
0176:
0177:
0178:
0179:
0180:
0181:
0182:
0183:
0184:
0185:
0186:
0187:
0188:
0189:
0190:
0191:
0192:
0193:
0194:
0195:
0196:
0197:
0198:
0199:
0200:
0201:
0202:
0203:
0204:
0205:
0206:
0207:
0208:
0209:
0210:
0211:
0212:
0213:
0214:
0215:
0216:
0217:
0218:
0219:
0220:
0221:
0222:
0223:
0224:
0225:
0226:
0227:
0228:
0229:
0230:
0231:
0232:
0233:
0234:
0235:
0236:
0237:
0238:
0239:
0240:
0241:
0242:
0243:
0244:
0245:
0246:
0247:
0248:
0249:
0250:
0251:
0252:
0253:
0254:
0255:
0256:
0257:
0258:
0259:
0260:
0261:
0262:
0263:
0264:
0265:
0266:
0267:
0268:
0269:
0270:
0271:
0272:
0273:
0274:
0275:
0276:
0277:
0278:
0279:
0280:
0281:
0282:
0283:
0284:
0285:
0286:
0287:
0288:
0289:
0290:
0291:
0292:
0293:
0294:
0295:
0296:
0297:
0298:
0299:
0300:
0301:
0302:
0303:
0304:
0305:
0306:
0307:
0308:
0309:
0310:
0311:
0312:
0313:
0314:
0315:
0316:
0317:
0318:
0319:
0320:
0321:
0322:
0323:
0324:
0325:
0326:
0327:
0328:
0329:
0330:
0331:
0332:
0333:
0334:
0335:
0336:
0337:
0338:
0339:
0340:
0341:
0342:
0343:
0344:
0345:
0346:
0347:
0348:
0349:
0350:
0351:
0352:
0353:
0354:
0355:
0356:
0357:
0358:
0359:
0360:
0361:
0362:
0363:
0364:
0365:
0366:
0367:
0368:
0369:
0370:
0371:
0372:
0373:
0374:
0375:
0376:
0377:
0378:
0379:
0380:
0381:
0382:
0383:
0384:
0385:
0386:
0387:
0388:
0389:
0390:
0391:
0392:
0393:
0394:
0395:
0396:
0397:
0398:
0399:
0400:
0401:
0402:
0403:
0404:
0405:
0406:
0407:
0408:
0409:
0410:
0411:
0412:
0413:
0414:
0415:
0416:
0417:
0418:
0419:
0420:
0421:
0422:
0423:
0424:
0425:
0426:
0427:
0428:
0429:
0430:
0431:
0432:
0433:
0434:
0435:
0436:
0437:
0438:
0439:
0440:
0441:
0442:
0443:
0444:
0445:
0446:
0447:
0448:
0449:
0450:
0451:
0452:
0453:
0454:
0455:
0456:
0457:
0458:
0459:
0460:
0461:
0462:
0463:
0464:
0465:
0466:
0467:
0468:
0469:
0470:
0471:
0472:
0473:
0474:
0475:
0476:
0477:
0478:
0479:
0480:
0481:
0482:
0483:
0484:
0485:
0486:
0487:
0488:
0489:
0490:
0491:
0492:
0493:
0494:
0495:
0496:
0497:
0498:
0499:
0500:
0501:
0502:
0503:
0504:
0505:
0506:
0507:
0508:
0509:
0510:
0511:
0512:
0513:
0514:
0515:
0516:
0517:
0518:
0519:
0520:
0521:
0522:
0523:
0524:
0525:
0526:
0527:
0528:
0529:
0530:
0531:
0532:
0533:
0534:
0535:
0536:
0537:
0538:
0539:
0540:
0541:
0542:
0543:
0544:
0545:
0546:
0547:
0548:
0549:
0550:
0551:
0552:
0553:
0554:
0555:
0556:
0557:
0558:
0559:
0560:
0561:
0562:
0563:
0564:
0565:
0566:
0567:
0568:
0569:
0570:
0571:
0572:
0573:
0574:
0575:
0576:
0577:
0578:
0579:
0580:
0581:
0582:
0583:
0584:
0585:
0586:
0587:
0588:
0589:
0590:
0591:
0592:
0593:
0594:
0595:
0596:
0597:
0598:
0599:
0600:
0601:
0602:
0603:
0604:
0605:
0606:
0607:
0608:
0609:
0610:
0611:
0612:
0613:
0614:
0615:
0616:
0617:
0618:
0619:
0620:
0621:
0622:
0623:
0624:
0625:
0626:
0627:
0628:
0629:
0630:
0631:
0632:
0633:
0634:
0635:
0636:
0637:
0638:
0639:
0640:
0641:
0642:
0643:
0644:
0645:
0646:
0647:
0648:
0649:
0650:
0651:
0652:
0653:
0654:
0655:
0656:
0657:
0658:
0659:
0660:
0661:
0662:
0663:
0664:
0665:
0666:
0667:
0668:
0669:
0670:
0671:
0672:
0673:
0674:
0675:
0676:
0677:
0678:
0679:
0680:
0681:
0682:
0683:
0684:
0685:
0686:
0687:
0688:
0689:
0690:
0691:
0692:
0693:
0694:
0695:
0696:
0697:
0698:
0699:
0700:
0701:
0702:
0703:
0704:
0705:
0706:
0707:
0708:
0709:
0710:
0711:
0712:
0713:
0714:
0715:
0716:
0717:
0718:
0719:
0720:
0721:
0722:
0723:
0724:
0725:
0726:
0727:
0728:
0729:
0730:
0731:
0732:
0733:
0734:
0735:
0736:
0737:
0738:
0739:
0740:
0741:
0742:
0743:
0744:
0745:
0746:
0747:
0748:
0749:
0750:
0751:
0752:
0753:
0754:
0755:
0756:
0757:
0758:
0759:
0760:
0761:
0762:
0763:
0764:
0765:
0766:
0767:
0768:
0769:
0770:
0771:
0772:
0773:
0774:
0775:
0776:
0777:
0778:
0779:
0780:
0781:
0782:
0783:
0784:
0785:
0786:
0787:
0788:
0789:
0790:
0791:
0792:
0793:
0794:
0795:
0796:
0797:
0798:
0799:
0800:
0801:
0802:
0803:
0804:
0805:
0806:
0807:
0808:
0809:
0810:
0811:
0812:
0813:
0814:
0815:
0816:
0817:
0818:
0819:
0820:
0821:
0822:
0823:
0824:
0825:
0826:
0827:
0828:
0829:
0830:
0831:
0832:
0833:
0834:
0835:
0836:
0837:
0838:
0839:
0840:
0841:
0842:
0843:
0844:
0845:
0846:
0847:
0848:
0849:
0850:
0851:
0852:
0853:
0854:
0855:
0856:
0857:
0858:
0859:
0860:
0861:
0862:
0863:
0864:
0865:
0866:
0867:
0868:
0869:
0870:
0871:
0872:
0873:
0874:
0875:
0876:
0877:
0878:
0879:
0880:
0881:
0882:
0883:
0884:
0885:
0886:
0887:
0888:
0889:
0890:
0891:
0892:
0893:
0894:
0895:
0896:
0897:
0898:
0899:
0900:
0901:
0902:
0903:
0904:
0905:
0906:
0907:
0908:
0909:
0910:
0911:
0912:
0913:
0914:
0915:
0916:
0917:
0918:
0919:
0920:
0921:
0922:
0923:
0924:
0925:
0926:
0927:
0928:
0929:
0930:
0931:
0932:
0933:
0934:
0935:
0936:
0937:
0938:
0939:
0940:
0941:
0942:
0943:
0944:
0945:
0946:
0947:
0948:
0949:
0950:
0951:
0952:
0953:
0954:
0955:
0956:
0957:
0958:
0959:
0960:
0961:
0962:
0963:
0964:
0965:
0966:
0967:
0968:
0969:
0970:
0971:
0972:
0973:
0974:
0975:
0976:
0977:
0978:
0979:
0980:
0981:
0982:
0983:
0984:
0985:
0986:
0987:
0988:
0989:
0990:
0991:
0992:
0993:
0994:
0995:
0996:
0997:
0998:
0999:
1000:
1001:
1002:
1003:
1004:
1005:
1006:
1007:
1008:
1009:
1010:
1011:
1012:
1013:
1014:
1015:
1016:
1017:
1018:
1019:
1020:
1021:
1022:
1023:
1024:
1025:
1026:
1027:
1028:
1029:
1030:
1031:
1032:
1033:
1034:
1035:
1036:
1037:
1038:
1039:
1040:
1041:
1042:
1043:
1044:
1045:
1046:
1047:
1048:
1049:
1050:
1051:
1052:
1053:
1054:
1055:
1056:
1057:
1058:
1059:
1060:
1061:
1062:
1063:
1064:
1065:
1066:
1067:
1068:
1069:
1070:
1071:
1072:
1073:
1074:
1075:
1076:
1077:
1078:
1079:
1080:
1081:
1082:
1083:
1084:
1085:
1086:
1087:
1088:
1089:
1090:
1091:
1092:
1093:
1094:
1095:
1096:
1097:
1098:
1099:
1100:
1101:
1102:
1103:
1104:
1105:
1106:
1107:
1108:
1109:
1110:
1111:
1112:
1113:
1114:
1115:
1116:
1117:
1118:
1119:
1120:
1121:
1122:
1123:
1124:
1125:
1126:
1127:
1128:
1129:
1130:
1131:
1132:
1133:
1134:
1135:
1136:
1137:
1138:
1139:
1140:
1141:
1142:
1143:
1144:
1145:
1146:
1147:
1148:
1149:
1150:
1151:
1152:
1153:
1154:
1155:
1156:
1157:
1158:
1159:
1160:
1161:
1162:
1163:
1164:
1165:
1166:
1167:
1168:
1169:
1170:
1171:
1172:
1173:
1174:
1175:
1176:
1177:
1178:
1179:
1180:
1181:
1182:
1183:
1184:
1185:
1186:
1187:
1188:
1189:
1190:
1191:
1192:
1193:
1194:
1195:
1196:
1197:
1198:
1199:
1200:
1201:
1202:
1203:
1204:
1205:
1206:
1207:
1208:
1209:
1210:
1211:
1212:
1213:
1214:
1215:
1216:
1217:
1218:
1219:
1220:
1221:
1222:
1223:
1224:
1225:
1226:
1227:
1228:
1229:
1230:
1231:
1232:
1233:
1234:
1235:
1236:
1237:
1238:
1239:
1240:
1241:
1242:
1243:
1244:
1245:
1246:
1247:
1248:
1249:
1250:
1251:
1252:
1253:
1254:
1255:
1256:
1257:
1258:
1259:
1260:
1261:
1262:
1263:
1264:
1265:
1266:
1267:
1268:
1269:
1270:
1271:
1272:
1273:
1274:
1275:
1276:
1277:
1278:
1279:
1280:
1281:
1282:
1283:
1284:
1285:
1286:
1287:
1288:
1289:
1290:
1291:
1292:
1293:
1294:
1295:
1296:
1297:
1298:
1299:
1300:
1301:
1302:
1303:
1304:
1305:
1306:
1307:
1308:
1309:
1310:
1311:
1312:
1313:
1314:
1315:
1316:
1317:
1318:
1319:
1320:
1321:
1322:
1323:
1324:
1325:
1326:
1327:
1328:
1329:
1330:
1331:
1332:
1333:
1334:
1335:
1336:
1337:
1338:
1339:
1340:
1341:
1342:
1343:
1344:
1345:
1346:
1347:
1348:
1349:
1350:
1351:
1352:
1353:
1354:
1355:
1356:
1357:
1358:
1359:
1360:
1361:
1362:
1363:
1364:
1365:
1366:
1367:
1368:
1369:
1370:
1371:
1372:
1373:
1374:
1375:
1376:
1377:
1378:
1379:
1380:
1381:
1382:
1383:
1384:
1385:
1386:
1387:
1388:
1389:
1390:
1391:
1392:
1393:
1394:
1395:
1396:
1397:
1398:
1399:
1400:
1401:
1402:
1403:
1404:
1405:
1406:
1407:
1408:
1409:
1410:
1411:
1412:
1413:
1414:
1415:
1416:
1417:
1418:
1419:
1420:
1421:
1422:
1423:
1424:
1425:
1426:
1427:
1428:
1429:
1430:
1431:
1432:
1433:
1434:
1435:
1436:
1437:
1438:
1439:
1440:
1441:
1442:
1443:
1444:
1445:
1446:
1447:
1448:
1449:
1450:
1451:
1452:
1453:
1454:
1455:
1456:
1457:
1458:
1459:
1460:
1461:
1462:
1463:
1464:
1465:
1466:
1467:
1468:
1469:
1470:
1471:
1472:
1473:
1474:
1475:
1476:
1477:
1478:
1479:
1480:
1481:
1482:
1483:
1484:
1485:
1486:
1487:
1488:
1489:
1490:
1491:
1492:
1493:
1494:
1495:
1496:
1497:
1498:
1499:
1500:
1501:
1502:
1503:
1504:
1505:
1506:
1507:
1508:
1509:
1510:
1511:
1512:
1513:
1514:
1515:
1516:
1517:
1518:
1519:
1520:
1521:
1522:
1523:
1524:
1525:
1526:
1527:
1528:
1529:
1530:
1531:
1532:
1533:
1534:
1535:
1536:
1537:
1538:
1539:
1540:
1541:
1542:
1543:
1544:
1545:
1546:
1547:
1548:
1549:
1550:
1551:
1552:
1553:
1554:
1555:
1556:
1557:
1558:
1559:
1560:
1561:
1562:
1563:
1564:
1565:
1566:
1567:
1568:
1569:
1570:
1571:
1572:
1573:
1574:
1575:
1576:
1577:
1578:
1579:
1580:
1581:
1582:
1583:
1584:
1585:
1586:
1587:
1588:
1589:
1590:
1591:
1592:
1593:
1594:
1595:
1596:
1597:
1598:
1599:
1600:
1601:
1602:
1603:
1604:
1605:
1606:
1607:
1608:
1609:
1610:
1611:
1612:
1613:
1614:
1615:
1616:
1617:
1618:
1619:
1620:
1621:
1622:
1623:
1624:
1625:
1626:
1627:
1628:
1629:
1630:
1631:
1632:
1633:
1634:
1635:
1636:
1637:
1638:
1639:
1640:
1641:
1642:
1643:
1644:
1645:
1646:
1647:
1648:
1649:
1650:
1651:
1652:
1653:
1654:
1655:
1656:
1657:
1658:
1659:
1660:
1661:
1662:
1663:
1664:
1665:
1666:
1667:
1668:
1669:
1670:
1671:
1672:
1673:
1674:
1675:
1676:
1677:
1678:
1679:
1680:
1681:
1682:
1683:
1684:
1685:
1686:
1687:
1688:
1689:
1690:
1691:
1692:
1693:
1694:
1695:
1696:
1697:
1698:
1699:
1700:
1701:
1702:
1703:
1704:
1705:
1706:
1707:
1708:
1709:
1710:
1711:
1712:
1713:
1714:
1715:
1716:
1717:
1718:
1719:
1720:
1721:
1722:
1723:
1724:
1725:
1726:
1727:
1728:
1729:
1730:
1731:



































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































/*
* Copyright (c), Zeriph Enterprises
* All rights reserved.
*
* Contributor(s):
* Zechariah Perez, omni (at) zeriph (dot) com
*
* THIS SOFTWARE IS PROVIDED BY ZERIPH AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ZERIPH AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <omni/sync/thread.hpp>
#if !defined(OMNI_OS_WIN)
    // need the following for POSIX thread set prio/join
    #include <unistd.h>
    #include <sched.h>
    #include <ctime>
    #include <cstring>
#endif
#include <omni/chrono/tick.hpp>
#include <omni/sync/scoped_lock.hpp>
#include <omni/consts/cconsts.hpp>
#include <omni/exception.hpp>

#if defined(OMNI_NON_PORTABLE)
    #define OMNI_PRIO_FW m_priority(omni::sync::thread_priority::NORMAL),
    #define OMNI_PRIO_CP_FW m_priority(cp.m_priority),
#else
    #define OMNI_PRIO_FW
    #define OMNI_PRIO_CP_FW
#endif
#if defined(OMNI_SAFE_THREAD)
    #define OMNI_SAFE_THREAD_MILST_FW m_mtx(),
    #define OMNI_SAFE_THREAD_LOCK_FW this->m_mtx.lock();
    #define OMNI_SAFE_THREAD_UNLOCK_FW this->m_mtx.unlock();
    #define OMNI_SAFE_THREAD_ALOCK_FW omni::sync::scoped_lock<omni::sync::basic_lock> smal(&this->m_mtx);
#else
    #define OMNI_SAFE_THREAD_MILST_FW
    #define OMNI_SAFE_THREAD_LOCK_FW
    #define OMNI_SAFE_THREAD_UNLOCK_FW
    #define OMNI_SAFE_THREAD_ALOCK_FW
#endif

namespace omni {
    namespace sync {
        typedef struct thread_args {
            omni::sync::thread* bthread;
            omni::sync::safe_spin_wait swait;
        } thread_args;
    }
}

//// start static thread management methods ////

void omni::sync::thread::manager::abort(omni::sync::thread_t tid)
{
    this->m_lock.lock();
    if (this->m_aborts.find(tid) != this->m_aborts.end()) {
        this->m_aborts[tid] = true;
    }
    this->m_lock.unlock();
}

bool omni::sync::thread::manager::abort_requested()
{
    bool ret = false;
    this->m_lock.lock();
    omni::sync::thread::manager::abort_map::iterator it = this->m_aborts.find(omni::sync::thread_id());
    if (it != this->m_aborts.end()) { ret = it->second; }
    this->m_lock.unlock();
    return ret;
}

void omni::sync::thread::manager::push_back(omni::sync::thread_t tid, omni::sync::thread& bthread)
{
    this->m_lock.lock();
    OMNI_DV5_FW("adding managed thread id: ", tid);
    this->m_threads[tid] = &bthread;
    this->m_aborts[tid] = false;
    this->m_lock.unlock();
}

void omni::sync::thread::manager::pop_back(omni::sync::thread_t tid)
{
    this->m_lock.lock();
    // erase the abort state first
    omni::sync::thread::manager::abort_map::iterator aitr = this->m_aborts.find(tid);
    if (aitr != this->m_aborts.end()) { this->m_aborts.erase(aitr); }
    omni::sync::thread::manager::thread_map::iterator itr = this->m_threads.find(tid);
    if (itr != this->m_threads.end()) {
        /* if the tid is still in the map, then the thread object is still attached to the
        state machine and it's safe to call the sate machine function on the thread object
        we grabbed from above */
        omni::sync::thread* t = itr->second;
        this->m_threads.erase(itr);
        this->m_lock.unlock();
        t->_state_machine();
    } else {
        this->m_lock.unlock();
    }
}

void omni::sync::thread::manager::remove(omni::sync::thread_t tid)
{
    this->m_lock.lock();
    omni::sync::thread::manager::thread_map::iterator it = this->m_threads.find(tid);
    if (it != this->m_threads.end()) {
        OMNI_DV5_FW("removing managed thread id: ", tid);
        this->m_threads.erase(it);
    }
    this->m_lock.unlock();
}

void omni::sync::thread::manager::request_abort(omni::sync::thread_t tid)
{
    bool found = false;
    this->m_lock.lock();
    omni::sync::thread::manager::thread_map::iterator itr = this->m_threads.find(tid);
    if (itr != this->m_threads.end()) {
        if (itr->second) {
            /* if the tid is still in the map, then the thread is still
            attached to the state machine (i.e. still being 'managed'), so
            grab the underlying thread object and call abort on it */
            omni::sync::thread* t = itr->second;
            found = true;
            this->m_lock.unlock();
            t->abort(); // calls the m_aborts[tid] = true;
        }
    }
    if (!found) {
        if (this->m_aborts.find(tid) != this->m_aborts.end()) {
            this->m_aborts[tid] = true;
        }
        this->m_lock.unlock();
    }
}

OMNI_THREAD_FNPTR_T OMNI_THREAD_CALL_T omni::sync::thread::_start(void* param)
{
    /* note: we don't call t->any_function() since that could potentially introduce a deadlock.
    If the thread gets this far, then the thread::start() function has already called scoped_lock
    and it's safe to use t->m_ values (since no other threads can operate on the values) */
    omni::sync::thread* t = (static_cast<omni::sync::thread_args*>(param))->bthread;
    if (t->m_mthd != OMNI_NULL) {
        omni::sync::thread_t tid = omni::sync::thread_id();
        omni::sync::parameterized_thread_start* pstartfn = OMNI_NULL;
        omni::sync::thread_start* startfn = OMNI_NULL;
        omni::sync::thread::manager::instance().push_back(tid, *t);
        if (t->m_ispmthd) {
            pstartfn = new omni::sync::parameterized_thread_start(*(static_cast<omni::sync::parameterized_thread_start*>(t->m_mthd)));
        } else {
            startfn = new omni::sync::thread_start(*(static_cast<omni::sync::thread_start*>(t->m_mthd)));
        }
        #if !defined(OMNI_OS_WIN)
            /*
                we don't check for any errors here as it's not a good idea to ever 'kill' a thread.
                setting to async cancel type sets the cross platform compatibility as TerminateThread
                is 'async' in nature.
                
                !!!! NOTE !!!!
                
                remember, it's a better idea to use 'abort' and the 'state_changed' handler to end
                your threads nicely (avoid resource leaks)
            */
            ::pthread_setcanceltype(PTHREAD_CANCEL_ASYNCHRONOUS, NULL);
        #endif
        #if defined(OMNI_NON_PORTABLE)
            if (t->m_priority != omni::sync::thread_priority::NORMAL) {
                OMNI_D4_FW("setting thread priority");
                t->_set_prio();
            }
        #endif
        t->m_state = omni::sync::thread_state::RUNNING;
        // wrap the delegate in a try..catch in case the user code errors, we can handle it here
        if (pstartfn != OMNI_NULL) {
            OMNI_THREAD_TRY_FW
            omni::sync::thread_arg_t args = t->m_args;
            (static_cast<omni::sync::thread_args*>(param))->swait.signal();
            pstartfn->invoke(args);
            OMNI_THREAD_CATCHEX_FW(delete pstartfn;)
        } else if (startfn != OMNI_NULL) {
            OMNI_THREAD_TRY_FW
            (static_cast<omni::sync::thread_args*>(param))->swait.signal();
            startfn->invoke();
            OMNI_THREAD_CATCHEX_FW(delete startfn;)
        }
        pstartfn = OMNI_NULL; startfn = OMNI_NULL;
        omni::sync::thread::manager::instance().pop_back(tid);
    } else {
        // shouldn't happen since this should be caught in the calling thread::start
        OMNI_DBGE(OMNI_INVALID_DELEGATE_FUNC_STR)
        OMNI_THROW_FW(omni::exceptions::invalid_delegate())        
        // if nothrow then act as 'killed'
        // DEV_NOTE: if OMNI_THROW_FW is defined, you might get warnings about this code being unreachable
        t->m_state = omni::sync::thread_state::STOPPED;
        (static_cast<omni::sync::thread_args*>(param))->swait.signal();
    }
    t = OMNI_NULL;
    return 0;
}

bool omni::sync::thread::abort_requested()
{
    return omni::sync::thread::manager::instance().abort_requested();
}

void omni::sync::thread::request_abort(omni::sync::thread_t tid)
{
    omni::sync::thread::manager::instance().request_abort(tid);
}

//// start thread constructors ////

omni::sync::thread::thread() :
    aborted(),
    completed(),
    OMNI_CTOR_FW(omni::sync::thread)
    OMNI_SAFE_THREAD_MILST_FW
    m_args(),
    m_mthd(OMNI_NULL),
    m_tid(0),
    m_thread(0),
    m_ops(),
    m_state(omni::sync::thread_state::UNSTARTED),
    OMNI_PRIO_FW
    m_isjoined(false),
    m_ispmthd(false)
{
    #if !defined(OMNI_CHRONO_AUTO_INIT_TICK)
        omni::chrono::monotonic::initialize();
    #endif
    this->m_ops.set_flag(omni::sync::thread_option::AUTO_JOIN, true);
    OMNI_D5_FW("thread created");
}

omni::sync::thread::thread(const omni::sync::thread &cp) :
    aborted(cp.aborted),
    completed(cp.completed),
    OMNI_CPCTOR_FW(cp)
    OMNI_SAFE_THREAD_MILST_FW
    m_args(cp.m_args),
    m_mthd(OMNI_NULL),
    m_tid(cp.m_tid),
    m_thread(cp.m_thread),
    m_ops(cp.m_ops),
    m_state(cp.m_state),
    OMNI_PRIO_CP_FW
    m_isjoined(cp.m_isjoined),
    m_ispmthd(cp.m_ispmthd)
{
    #if !defined(OMNI_CHRONO_AUTO_INIT_TICK)
        omni::chrono::monotonic::initialize();
    #endif
    this->m_ops.set_flag(omni::sync::thread_option::AUTO_JOIN, true);
    if (cp.m_mthd != OMNI_NULL) {
        if (cp.m_ispmthd) {
            this->m_mthd = new omni::sync::parameterized_thread_start(*(static_cast<omni::sync::parameterized_thread_start*>(cp.m_mthd)));
        } else {
            this->m_mthd = new omni::sync::thread_start(*(static_cast<omni::sync::thread_start*>(cp.m_mthd)));
        }
    }
    OMNI_D5_FW("thread copied");
}

omni::sync::thread::thread(const omni::sync::thread_flags &ops) :
    aborted(),
    completed(),
    OMNI_CTOR_FW(omni::sync::thread)
    OMNI_SAFE_THREAD_MILST_FW
    m_args(),
    m_mthd(OMNI_NULL),
    m_tid(0),
    m_thread(0),
    m_ops(ops),
    m_state(omni::sync::thread_state::UNSTARTED),
    OMNI_PRIO_FW
    m_isjoined(false),
    m_ispmthd(false)
{
    #if !defined(OMNI_CHRONO_AUTO_INIT_TICK)
        omni::chrono::monotonic::initialize();
    #endif
    OMNI_D5_FW("thread const copied");
}

omni::sync::thread::thread(std::size_t max_stack_sz) :
    aborted(),
    completed(),
    OMNI_CTOR_FW(omni::sync::thread)
    OMNI_SAFE_THREAD_MILST_FW
    m_args(),
    m_mthd(OMNI_NULL),
    m_tid(0),
    m_thread(0),
    m_ops(max_stack_sz),
    m_state(omni::sync::thread_state::UNSTARTED),
    OMNI_PRIO_FW
    m_isjoined(false),
    m_ispmthd(false)
{
    #if !defined(OMNI_CHRONO_AUTO_INIT_TICK)
        omni::chrono::monotonic::initialize();
    #endif
    this->m_ops.set_flag(omni::sync::thread_option::AUTO_JOIN, true);
    OMNI_DV5_FW("thread created with stack size of ", this->m_ops.stack_size());
}

omni::sync::thread::thread(const omni::sync::thread_start &mthd) :
    aborted(),
    completed(),
    OMNI_CTOR_FW(omni::sync::thread)
    OMNI_SAFE_THREAD_MILST_FW
    m_args(),
    m_mthd(new omni::sync::thread_start(mthd)),
    m_tid(0),
    m_thread(0),
    m_ops(),
    m_state(omni::sync::thread_state::UNSTARTED),
    OMNI_PRIO_FW
    m_isjoined(false),
    m_ispmthd(false)
{
    #if !defined(OMNI_CHRONO_AUTO_INIT_TICK)
        omni::chrono::monotonic::initialize();
    #endif
    this->m_ops.set_flag(omni::sync::thread_option::AUTO_JOIN, true);
    OMNI_D5_FW("thread created with delegate method");
}

omni::sync::thread::thread(const omni::sync::thread_start &mthd, const omni::sync::thread::delegate& abort_req) :
    aborted(abort_req),
    completed(),
    OMNI_CTOR_FW(omni::sync::thread)
    OMNI_SAFE_THREAD_MILST_FW
    m_args(),
    m_mthd(new omni::sync::thread_start(mthd)),
    m_tid(0),
    m_thread(0),
    m_ops(),
    m_state(omni::sync::thread_state::UNSTARTED),
    OMNI_PRIO_FW
    m_isjoined(false),
    m_ispmthd(false)
{
    #if !defined(OMNI_CHRONO_AUTO_INIT_TICK)
        omni::chrono::monotonic::initialize();
    #endif
    this->m_ops.set_flag(omni::sync::thread_option::AUTO_JOIN, true);
    OMNI_D5_FW("thread created with delegate method");
}

omni::sync::thread::thread(const omni::sync::thread_start &mthd, const omni::sync::thread::delegate& abort_req, const omni::sync::thread::delegate& comp) :
    aborted(abort_req),
    completed(comp),
    OMNI_CTOR_FW(omni::sync::thread)
    OMNI_SAFE_THREAD_MILST_FW
    m_args(),
    m_mthd(new omni::sync::thread_start(mthd)),
    m_tid(0),
    m_thread(0),
    m_ops(),
    m_state(omni::sync::thread_state::UNSTARTED),
    OMNI_PRIO_FW
    m_isjoined(false),
    m_ispmthd(false)
{
    #if !defined(OMNI_CHRONO_AUTO_INIT_TICK)
        omni::chrono::monotonic::initialize();
    #endif
    this->m_ops.set_flag(omni::sync::thread_option::AUTO_JOIN, true);
    OMNI_D5_FW("thread created with delegate method");
}

omni::sync::thread::thread(const omni::sync::thread_start& mthd, omni::sync::thread_start_type::enum_t st) :
    aborted(),
    completed(),
    OMNI_CTOR_FW(omni::sync::thread)
    OMNI_SAFE_THREAD_MILST_FW
    m_args(),
    m_mthd(new omni::sync::thread_start(mthd)),
    m_tid(0),
    m_thread(0),
    m_ops(),
    m_state(omni::sync::thread_state::UNSTARTED),
    OMNI_PRIO_FW
    m_isjoined(false),
    m_ispmthd(false)
{
    #if !defined(OMNI_CHRONO_AUTO_INIT_TICK)
        omni::chrono::monotonic::initialize();
    #endif
    this->m_ops.set_flag(omni::sync::thread_option::AUTO_JOIN, true);
    OMNI_D5_FW("thread created with delegate method");
    if (st == omni::sync::thread_start_type::NOW) {
        this->start();
    }
}

omni::sync::thread::thread(const omni::sync::thread_start& mthd, const omni::sync::thread::delegate& abort_req, omni::sync::thread_start_type::enum_t st) :
    aborted(abort_req),
    completed(),
    OMNI_CTOR_FW(omni::sync::thread)
    OMNI_SAFE_THREAD_MILST_FW
    m_args(),
    m_mthd(new omni::sync::thread_start(mthd)),
    m_tid(0),
    m_thread(0),
    m_ops(),
    m_state(omni::sync::thread_state::UNSTARTED),
    OMNI_PRIO_FW
    m_isjoined(false),
    m_ispmthd(false)
{
    #if !defined(OMNI_CHRONO_AUTO_INIT_TICK)
        omni::chrono::monotonic::initialize();
    #endif
    this->m_ops.set_flag(omni::sync::thread_option::AUTO_JOIN, true);
    OMNI_D5_FW("thread created with delegate method");
    if (st == omni::sync::thread_start_type::NOW) {
        this->start();
    }
}

omni::sync::thread::thread(const omni::sync::thread_start& mthd, const omni::sync::thread::delegate& abort_req, const omni::sync::thread::delegate& comp, omni::sync::thread_start_type::enum_t st) :
    aborted(abort_req),
    completed(comp),
    OMNI_CTOR_FW(omni::sync::thread)
    OMNI_SAFE_THREAD_MILST_FW
    m_args(),
    m_mthd(new omni::sync::thread_start(mthd)),
    m_tid(0),
    m_thread(0),
    m_ops(),
    m_state(omni::sync::thread_state::UNSTARTED),
    OMNI_PRIO_FW
    m_isjoined(false),
    m_ispmthd(false)
{
    #if !defined(OMNI_CHRONO_AUTO_INIT_TICK)
        omni::chrono::monotonic::initialize();
    #endif
    this->m_ops.set_flag(omni::sync::thread_option::AUTO_JOIN, true);
    OMNI_D5_FW("thread created with delegate method");
    if (st == omni::sync::thread_start_type::NOW) {
        this->start();
    }
}

omni::sync::thread::thread(const omni::sync::thread_start &mthd, std::size_t max_stack_sz) :
    aborted(),
    completed(),
    OMNI_CTOR_FW(omni::sync::thread)
    OMNI_SAFE_THREAD_MILST_FW
    m_args(),
    m_mthd(new omni::sync::thread_start(mthd)),
    m_tid(0),
    m_thread(0),
    m_ops(max_stack_sz),
    m_state(omni::sync::thread_state::UNSTARTED),
    OMNI_PRIO_FW
    m_isjoined(false),
    m_ispmthd(false)
{
    #if !defined(OMNI_CHRONO_AUTO_INIT_TICK)
        omni::chrono::monotonic::initialize();
    #endif
    this->m_ops.set_flag(omni::sync::thread_option::AUTO_JOIN, true);
    OMNI_DV5_FW("thread created with stack size of ", this->m_ops.stack_size());
}

omni::sync::thread::thread(const omni::sync::thread_start &mthd, const omni::sync::thread::delegate& abort_req, std::size_t max_stack_sz) :
    aborted(abort_req),
    completed(),
    OMNI_CTOR_FW(omni::sync::thread)
    OMNI_SAFE_THREAD_MILST_FW
    m_args(),
    m_mthd(new omni::sync::thread_start(mthd)),
    m_tid(0),
    m_thread(0),
    m_ops(max_stack_sz),
    m_state(omni::sync::thread_state::UNSTARTED),
    OMNI_PRIO_FW
    m_isjoined(false),
    m_ispmthd(false)
{
    #if !defined(OMNI_CHRONO_AUTO_INIT_TICK)
        omni::chrono::monotonic::initialize();
    #endif
    this->m_ops.set_flag(omni::sync::thread_option::AUTO_JOIN, true);
    OMNI_DV5_FW("thread created with stack size of ", this->m_ops.stack_size());
}

omni::sync::thread::thread(const omni::sync::thread_start &mthd, const omni::sync::thread::delegate& abort_req, const omni::sync::thread::delegate& comp, std::size_t max_stack_sz) :
    aborted(abort_req),
    completed(comp),
    OMNI_CTOR_FW(omni::sync::thread)
    OMNI_SAFE_THREAD_MILST_FW
    m_args(),
    m_mthd(new omni::sync::thread_start(mthd)),
    m_tid(0),
    m_thread(0),
    m_ops(max_stack_sz),
    m_state(omni::sync::thread_state::UNSTARTED),
    OMNI_PRIO_FW
    m_isjoined(false),
    m_ispmthd(false)
{
    #if !defined(OMNI_CHRONO_AUTO_INIT_TICK)
        omni::chrono::monotonic::initialize();
    #endif
    this->m_ops.set_flag(omni::sync::thread_option::AUTO_JOIN, true);
    OMNI_DV5_FW("thread created with stack size of ", this->m_ops.stack_size());
}

omni::sync::thread::thread(const omni::sync::thread_start &mthd, std::size_t max_stack_sz, omni::sync::thread_start_type::enum_t st) :
    aborted(),
    completed(),
    OMNI_CTOR_FW(omni::sync::thread)
    OMNI_SAFE_THREAD_MILST_FW
    m_args(),
    m_mthd(new omni::sync::thread_start(mthd)),
    m_tid(0),
    m_thread(0),
    m_ops(max_stack_sz),
    m_state(omni::sync::thread_state::UNSTARTED),
    OMNI_PRIO_FW
    m_isjoined(false),
    m_ispmthd(false)
{
    #if !defined(OMNI_CHRONO_AUTO_INIT_TICK)
        omni::chrono::monotonic::initialize();
    #endif
    this->m_ops.set_flag(omni::sync::thread_option::AUTO_JOIN, true);
    OMNI_DV5_FW("thread created with stack size of ", this->m_ops.stack_size());
    if (st == omni::sync::thread_start_type::NOW) {
        this->start();
    }
}

omni::sync::thread::thread(const omni::sync::thread_start &mthd, const omni::sync::thread::delegate& abort_req, std::size_t max_stack_sz, omni::sync::thread_start_type::enum_t st) :
    aborted(abort_req),
    completed(),
    OMNI_CTOR_FW(omni::sync::thread)
    OMNI_SAFE_THREAD_MILST_FW
    m_args(),
    m_mthd(new omni::sync::thread_start(mthd)),
    m_tid(0),
    m_thread(0),
    m_ops(max_stack_sz),
    m_state(omni::sync::thread_state::UNSTARTED),
    OMNI_PRIO_FW
    m_isjoined(false),
    m_ispmthd(false)
{
    #if !defined(OMNI_CHRONO_AUTO_INIT_TICK)
        omni::chrono::monotonic::initialize();
    #endif
    this->m_ops.set_flag(omni::sync::thread_option::AUTO_JOIN, true);
    OMNI_DV5_FW("thread created with stack size of ", this->m_ops.stack_size());
    if (st == omni::sync::thread_start_type::NOW) {
        this->start();
    }
}

omni::sync::thread::thread(const omni::sync::thread_start &mthd, const omni::sync::thread::delegate& abort_req, const omni::sync::thread::delegate& comp, std::size_t max_stack_sz, omni::sync::thread_start_type::enum_t st) :
    aborted(abort_req),
    completed(comp),
    OMNI_CTOR_FW(omni::sync::thread)
    OMNI_SAFE_THREAD_MILST_FW
    m_args(),
    m_mthd(new omni::sync::thread_start(mthd)),
    m_tid(0),
    m_thread(0),
    m_ops(max_stack_sz),
    m_state(omni::sync::thread_state::UNSTARTED),
    OMNI_PRIO_FW
    m_isjoined(false),
    m_ispmthd(false)
{
    #if !defined(OMNI_CHRONO_AUTO_INIT_TICK)
        omni::chrono::monotonic::initialize();
    #endif
    this->m_ops.set_flag(omni::sync::thread_option::AUTO_JOIN, true);
    OMNI_DV5_FW("thread created with stack size of ", this->m_ops.stack_size());
    if (st == omni::sync::thread_start_type::NOW) {
        this->start();
    }
}

omni::sync::thread::thread(const omni::sync::thread_start& mthd, omni::sync::thread_option::enum_t op, omni::sync::thread_union_t val) :
    aborted(),
    completed(),
    OMNI_CTOR_FW(omni::sync::thread)
    OMNI_SAFE_THREAD_MILST_FW
    m_args(),
    m_mthd(new omni::sync::thread_start(mthd)),
    m_tid(0),
    m_thread(0),
    m_ops(),
    m_state(omni::sync::thread_state::UNSTARTED),
    OMNI_PRIO_FW
    m_isjoined(false),
    m_ispmthd(false)
{
    #if !defined(OMNI_CHRONO_AUTO_INIT_TICK)
        omni::chrono::monotonic::initialize();
    #endif
    this->m_ops.set_flag(omni::sync::thread_option::AUTO_JOIN, true);
    OMNI_D5_FW("thread created with specific options");
    this->set_option(op, val);
}

// parameterized thread start constructors

omni::sync::thread::thread(const omni::sync::parameterized_thread_start &mthd) :
    aborted(),
    completed(),
    OMNI_CTOR_FW(omni::sync::thread)
    OMNI_SAFE_THREAD_MILST_FW
    m_args(),
    m_mthd(new omni::sync::parameterized_thread_start(mthd)),
    m_tid(0),
    m_thread(0),
    m_ops(),
    m_state(omni::sync::thread_state::UNSTARTED),
    OMNI_PRIO_FW
    m_isjoined(false),
    m_ispmthd(true)
{
    #if !defined(OMNI_CHRONO_AUTO_INIT_TICK)
        omni::chrono::monotonic::initialize();
    #endif
    this->m_ops.set_flag(omni::sync::thread_option::AUTO_JOIN, true);
    OMNI_D5_FW("thread created with delegate method");
}

omni::sync::thread::thread(const omni::sync::parameterized_thread_start &mthd, const omni::sync::thread::delegate& abort_req) :
    aborted(abort_req),
    completed(),
    OMNI_CTOR_FW(omni::sync::thread)
    OMNI_SAFE_THREAD_MILST_FW
    m_args(),
    m_mthd(new omni::sync::parameterized_thread_start(mthd)),
    m_tid(0),
    m_thread(0),
    m_ops(),
    m_state(omni::sync::thread_state::UNSTARTED),
    OMNI_PRIO_FW
    m_isjoined(false),
    m_ispmthd(true)
{
    #if !defined(OMNI_CHRONO_AUTO_INIT_TICK)
        omni::chrono::monotonic::initialize();
    #endif
    this->m_ops.set_flag(omni::sync::thread_option::AUTO_JOIN, true);
    OMNI_D5_FW("thread created with delegate method");
}

omni::sync::thread::thread(const omni::sync::parameterized_thread_start &mthd, const omni::sync::thread::delegate& abort_req, const omni::sync::thread::delegate& comp) :
    aborted(abort_req),
    completed(comp),
    OMNI_CTOR_FW(omni::sync::thread)
    OMNI_SAFE_THREAD_MILST_FW
    m_args(),
    m_mthd(new omni::sync::parameterized_thread_start(mthd)),
    m_tid(0),
    m_thread(0),
    m_ops(),
    m_state(omni::sync::thread_state::UNSTARTED),
    OMNI_PRIO_FW
    m_isjoined(false),
    m_ispmthd(true)
{
    #if !defined(OMNI_CHRONO_AUTO_INIT_TICK)
        omni::chrono::monotonic::initialize();
    #endif
    this->m_ops.set_flag(omni::sync::thread_option::AUTO_JOIN, true);
    OMNI_D5_FW("thread created with delegate method");
}

omni::sync::thread::thread(const omni::sync::parameterized_thread_start &mthd, std::size_t max_stack_sz) :
    aborted(),
    completed(),
    OMNI_CTOR_FW(omni::sync::thread)
    OMNI_SAFE_THREAD_MILST_FW
    m_args(),
    m_mthd(new omni::sync::parameterized_thread_start(mthd)),
    m_tid(0),
    m_thread(0),
    m_ops(max_stack_sz),
    m_state(omni::sync::thread_state::UNSTARTED),
    OMNI_PRIO_FW
    m_isjoined(false),
    m_ispmthd(true)
{
    #if !defined(OMNI_CHRONO_AUTO_INIT_TICK)
        omni::chrono::monotonic::initialize();
    #endif
    this->m_ops.set_flag(omni::sync::thread_option::AUTO_JOIN, true);
    OMNI_DV5_FW("thread created with stack size of ", this->m_ops.stack_size());
}

omni::sync::thread::thread(const omni::sync::parameterized_thread_start &mthd, const omni::sync::thread::delegate& abort_req, std::size_t max_stack_sz) :
    aborted(abort_req),
    completed(),
    OMNI_CTOR_FW(omni::sync::thread)
    OMNI_SAFE_THREAD_MILST_FW
    m_args(),
    m_mthd(new omni::sync::parameterized_thread_start(mthd)),
    m_tid(0),
    m_thread(0),
    m_ops(max_stack_sz),
    m_state(omni::sync::thread_state::UNSTARTED),
    OMNI_PRIO_FW
    m_isjoined(false),
    m_ispmthd(true)
{
    #if !defined(OMNI_CHRONO_AUTO_INIT_TICK)
        omni::chrono::monotonic::initialize();
    #endif
    this->m_ops.set_flag(omni::sync::thread_option::AUTO_JOIN, true);
    OMNI_DV5_FW("thread created with stack size of ", this->m_ops.stack_size());
}

omni::sync::thread::thread(const omni::sync::parameterized_thread_start &mthd, const omni::sync::thread::delegate& abort_req, const omni::sync::thread::delegate& comp, std::size_t max_stack_sz) :
    aborted(abort_req),
    completed(comp),
    OMNI_CTOR_FW(omni::sync::thread)
    OMNI_SAFE_THREAD_MILST_FW
    m_args(),
    m_mthd(new omni::sync::parameterized_thread_start(mthd)),
    m_tid(0),
    m_thread(0),
    m_ops(max_stack_sz),
    m_state(omni::sync::thread_state::UNSTARTED),
    OMNI_PRIO_FW
    m_isjoined(false),
    m_ispmthd(true)
{
    #if !defined(OMNI_CHRONO_AUTO_INIT_TICK)
        omni::chrono::monotonic::initialize();
    #endif
    this->m_ops.set_flag(omni::sync::thread_option::AUTO_JOIN, true);
    OMNI_DV5_FW("thread created with stack size of ", this->m_ops.stack_size());
}

omni::sync::thread::thread(const omni::sync::parameterized_thread_start& mthd, omni::sync::thread_option::enum_t op, omni::sync::thread_union_t val) :
    aborted(),
    completed(),
    OMNI_CTOR_FW(omni::sync::thread)
    OMNI_SAFE_THREAD_MILST_FW
    m_args(),
    m_mthd(new omni::sync::parameterized_thread_start(mthd)),
    m_tid(0),
    m_thread(0),
    m_ops(),
    m_state(omni::sync::thread_state::UNSTARTED),
    OMNI_PRIO_FW
    m_isjoined(false),
    m_ispmthd(true)
{
    #if !defined(OMNI_CHRONO_AUTO_INIT_TICK)
        omni::chrono::monotonic::initialize();
    #endif
    this->m_ops.set_flag(omni::sync::thread_option::AUTO_JOIN, true);
    OMNI_D5_FW("thread created with specific options");
    this->set_option(op, val);
}

//// end thread constructors ////

omni::sync::thread::~thread()
{
    OMNI_D5_FW("thread tearing down");
    OMNI_TRY_FW
    OMNI_DTOR_FW
    OMNI_SAFE_THREAD_LOCK_FW
    bool do_detach = true;
    if (this->_hvalid() && this->_state_running()) {
        if (this->m_ops.detach_on_destroy()) {
            this->_hreset(true, false); // detach
            do_detach = false;
        } else {
            if (this->m_ops.abort_on_destroy()) {
                OMNI_D5_FW("abort on destroy");
                this->m_state = omni::sync::thread_state::ABORT_REQUESTED;
                omni::sync::thread::manager::instance().abort(this->m_tid);
                OMNI_SAFE_THREAD_UNLOCK_FW
                if (this->aborted) { this->aborted(*this); }
                OMNI_SAFE_THREAD_LOCK_FW
            }
            if (this->m_ops.auto_join()) {
                OMNI_D5_FW("auto join");
                std::size_t to = this->m_ops.auto_join_timeout();
                if (to > 0) {
                    bool kod = this->m_ops.kill_on_destroy();
                    OMNI_SAFE_THREAD_UNLOCK_FW
                    this->join(static_cast<uint32_t>(to));
                    if (kod) { this->kill(); }
                    OMNI_SAFE_THREAD_LOCK_FW
                } else {
                    OMNI_SAFE_THREAD_UNLOCK_FW
                    this->join();
                    OMNI_SAFE_THREAD_LOCK_FW
                }
            } else {
                if (this->m_ops.kill_on_destroy()) {
                    OMNI_D5_FW("killing");
                    OMNI_SAFE_THREAD_UNLOCK_FW
                    this->kill();
                    OMNI_SAFE_THREAD_LOCK_FW
                }
            }
        }
    }
    if (do_detach) { this->_hreset(true, false); }
    this->_chkmthd();
    OMNI_SAFE_THREAD_UNLOCK_FW
    OMNI_CATCH_FW
    OMNI_D5_FW("destroyed");
}

void omni::sync::thread::abort()
{
    OMNI_SAFE_THREAD_LOCK_FW
    bool valid = this->_hvalid();
    bool running = this->_state_running();
    OMNI_SAFE_THREAD_UNLOCK_FW
    if (!valid) { OMNI_ERR_FW(OMNI_INVALID_THREAD_HANDLE_STR, omni::exceptions::invalid_thread_handle()) }
    if (running) { this->_state_changed(omni::sync::thread_state::ABORT_REQUESTED); }
    #if defined(OMNI_DBG_L3)
    else { OMNI_D3_FW("thread is not running"); }
    #endif
}

bool omni::sync::thread::abort_join()
{
    this->abort();
    return this->join();
}

bool omni::sync::thread::abort_join(uint32_t timeout)
{
    this->abort();
    return this->join(timeout);
}

bool omni::sync::thread::bind(const omni::sync::parameterized_thread_start& mthd)
{
    if (!this->unbind()) { return false; }
    OMNI_SAFE_THREAD_LOCK_FW
    this->m_mthd = new omni::sync::parameterized_thread_start(mthd);
    this->m_ispmthd = true;
    OMNI_SAFE_THREAD_UNLOCK_FW
    return true;
}

bool omni::sync::thread::bind(const omni::sync::thread_start& mthd)
{
    if (!this->unbind()) { return false; }
    OMNI_SAFE_THREAD_LOCK_FW
    this->m_mthd = new omni::sync::thread_start(mthd);
    OMNI_SAFE_THREAD_UNLOCK_FW
    return true;
}

void omni::sync::thread::detach()
{
    this->detach(false);
}

void omni::sync::thread::detach(bool allow_rejoin)
{
    OMNI_SAFE_THREAD_ALOCK_FW
    this->_hreset(true, allow_rejoin);
}

const omni::sync::thread_union_t omni::sync::thread::get_option(omni::sync::thread_option::enum_t op) const
{
    OMNI_SAFE_THREAD_ALOCK_FW
    switch (op) {
        case omni::sync::thread_option::ALLOW_THREAD_REUSE:
            return this->m_ops.allow_reuse();
        case omni::sync::thread_option::AUTO_JOIN:
            return this->m_ops.auto_join();
        case omni::sync::thread_option::DETACH_ON_DESTROY:
            return this->m_ops.detach_on_destroy();
        case omni::sync::thread_option::ABORT_ON_DESTROY:
            return this->m_ops.abort_on_destroy();
        case omni::sync::thread_option::KILL_ON_DESTROY:
            return this->m_ops.kill_on_destroy();
        case omni::sync::thread_option::DETACH_ON_ASSIGN:
            return this->m_ops.detach_on_assign();
        case omni::sync::thread_option::ABORT_ON_ASSIGN:
            return this->m_ops.abort_on_assign();
        case omni::sync::thread_option::KILL_ON_ASSIGN:
            return this->m_ops.kill_on_assign();
        case omni::sync::thread_option::STACK_SIZE:
            return this->m_ops.stack_size();
        case omni::sync::thread_option::AUTO_JOIN_TIMEOUT:
            return this->m_ops.auto_join_timeout();
        case omni::sync::thread_option::NONE:
        default: // invalid_option
            OMNI_ERRV_FW("invalid option: ", op, omni::exceptions::invalid_thread_option(static_cast<std::size_t>(op)))
            break;
    }
    return false;
}

omni::sync::thread_flags omni::sync::thread::options() const
{
    OMNI_SAFE_THREAD_ALOCK_FW
    return this->m_ops;
}

omni::sync::thread_handle_t omni::sync::thread::handle() const
{
    OMNI_SAFE_THREAD_ALOCK_FW
    return this->m_thread;
}

omni::sync::thread_t omni::sync::thread::id() const
{
    OMNI_SAFE_THREAD_ALOCK_FW
    return this->m_tid;
}

bool omni::sync::thread::is_alive() const
{
    OMNI_SAFE_THREAD_ALOCK_FW
    /*
    DEV_NOTE: we don't use pthread_kill or GetExitCodeThread
    since those might give 'erroneous' results for these purposes.
    That is to say, using JUST those API's will not guarantee
    that our underlying thread is 'actually' running.
    
    omni::sync::thread_state::UNSTARTED = 0,
    // Defines a thread has completed its function (method complete)
    omni::sync::thread_state::COMPLETED = 4,
    // Defines a thread is stopped (killed)
    omni::sync::thread_state::STOPPED = 16,
    // Defines a thread has been aborted
    omni::sync::thread_state::ABORTED = 64,
    // Defines a thread is attempting to spawn
    omni::sync::thread_state::START_REQUESTED = 1,
    
    // Defines a thread is running (method has been called)
    omni::sync::thread_state::RUNNING = 2,
    // Defines a thread has a stop request (kill request)
    omni::sync::thread_state::STOP_REQUESTED = 8,
    // Defines a thread has an abort request
    omni::sync::thread_state::ABORT_REQUESTED = 32,
    // Defines a thread has a state that can not be determined (when creating threads from handles for instance)
    omni::sync::thread_state::UNKNOWN = 255
    */
    return this->_hvalid() && this->_state_running();
}

bool omni::sync::thread::is_bound() const
{
    OMNI_SAFE_THREAD_ALOCK_FW
    if (this->m_mthd != OMNI_NULL) {
        if (this->m_ispmthd) {
            return (static_cast<omni::sync::parameterized_thread_start*>(this->m_mthd))->valid();
        } else {
            return (static_cast<omni::sync::thread_start*>(this->m_mthd))->valid();
        }
    }
    return false;
}

bool omni::sync::thread::is_parameter_bound() const
{
    OMNI_SAFE_THREAD_ALOCK_FW
    if (this->m_ispmthd) {
        return (static_cast<omni::sync::parameterized_thread_start*>(this->m_mthd))->valid();
    }
    return false;
}

bool omni::sync::thread::is_detached() const
{
    OMNI_SAFE_THREAD_ALOCK_FW
    return (this->m_state == omni::sync::thread_state::UNSTARTED &&
            this->m_tid == 0 &&
            this->m_thread == 0);
}

bool omni::sync::thread::join()
{
    return this->join(omni::sync::INFINITE_TIMEOUT);
}

bool omni::sync::thread::join(uint32_t timeout)
{
    // Unknown states can still be joined
    if (!this->is_alive()) {
        OMNI_D2_FW("thread is not running");
        return true;
    }
    OMNI_SAFE_THREAD_LOCK_FW
    if (!this->_hvalid()) {
        OMNI_SAFE_THREAD_UNLOCK_FW
        OMNI_ERR_RETV_FW(OMNI_INVALID_THREAD_HANDLE_STR, omni::exceptions::invalid_thread_handle(), false)
    }
    omni::sync::thread_handle_t hndl = this->m_thread;
    if (hndl == omni::sync::thread_handle()) {
        OMNI_SAFE_THREAD_UNLOCK_FW
        OMNI_ERR_RETV_FW(OMNI_INVALID_THREAD_OWNER, omni::exceptions::invalid_thread_owner(), false)
    }
    #if defined(OMNI_OS_WIN)
        this->m_isjoined = true;
        OMNI_SAFE_THREAD_UNLOCK_FW
        return (
            (::WaitForSingleObject(OMNI_WIN_TOHNDL_FW(hndl), timeout) == 0) ? true :
            #if !defined(OMNI_DBG_L1)
                false
            #else
                !(OMNI_DBGEV_FW("error while waiting for thread handle: ", OMNI_GLE_PRNT))
            #endif
        );
    #else
        /* There is not a portable mechanism with pthreads to wait on a specific thread without
        implementing a timed_wait condition variable. We don't want the user to have to implement
        a seperate variable based on system, so we implement a 'timeout' loop*/
        this->m_isjoined = true;
        OMNI_SAFE_THREAD_UNLOCK_FW
        if (timeout != omni::sync::INFINITE_TIMEOUT) {
            OMNI_SLEEP_INIT();
            volatile bool iav = true;
            omni::chrono::tick_t ts = omni::chrono::monotonic_tick();
            // iav = (::pthread_kill(hndl, 0) != ESRCH); // == "alive"
            while ((iav = (::pthread_kill(hndl, 0) != ESRCH)) && (omni::chrono::elapsed_ms(ts) < timeout)) {
                OMNI_SLEEP1();
            }
            return (::pthread_kill(hndl, 0) == ESRCH); // == "dead"
        }
        return (
            (::pthread_join(hndl, NULL) == 0) ? true :
            #if !defined(OMNI_DBG_L1)
                false
            #else
                !(OMNI_DBGEV_FW("error while waiting for thread handle: ", OMNI_GLE_PRNT))
            #endif
        );
    #endif
}

bool omni::sync::thread::join(const omni::chrono::unsigned_timespan& span)
{
    return this->join(static_cast<uint32_t>(span.total_milliseconds()));
}

bool omni::sync::thread::kill()
{
    if (!this->is_alive()) {
        // thread's already 'dead', no need to 'kill'
        OMNI_D2_FW("thread is not running");
        return true;
    }
    OMNI_SAFE_THREAD_LOCK_FW
    if (!this->_hvalid()) {
        OMNI_SAFE_THREAD_UNLOCK_FW
        OMNI_ERR_RETV_FW(OMNI_INVALID_THREAD_HANDLE_STR, omni::exceptions::invalid_thread_handle(), false)
    }
    int perr = 0;
    omni::sync::thread_handle_t hndl = this->m_thread;
    if (hndl == omni::sync::thread_handle()) {
        OMNI_SAFE_THREAD_UNLOCK_FW
        OMNI_ERR_RETV_FW(OMNI_INVALID_THREAD_OWNER, omni::exceptions::invalid_thread_owner(), false)
    }
    this->m_state = omni::sync::thread_state::STOP_REQUESTED;
    OMNI_SAFE_THREAD_UNLOCK_FW
    // attempt to kill it
    #if defined(OMNI_OS_WIN)
        if (::TerminateThread(OMNI_WIN_TOHNDL_FW(hndl), 0) == 0) {
            perr = OMNI_GLE;
        }
    #else
        perr = ::pthread_cancel(hndl);
    #endif
    if (perr == 0) {
        this->_state_changed(omni::sync::thread_state::STOPPED);
        return true;
    }
    OMNI_DV1_FW("thread termination error code: ", perr);
    // Something unknown happened...
    OMNI_SAFE_THREAD_LOCK_FW
    this->m_state = omni::sync::thread_state::UNKNOWN;
    OMNI_SAFE_THREAD_UNLOCK_FW
    return false;
}

bool omni::sync::thread::reset()
{
    if (this->is_alive()) {        
        OMNI_ERR_RETV_FW("cannot reset thread while running", omni::exceptions::thread_running_exception(), false)
    } else {
        this->detach();
    }
    return true;
}

bool omni::sync::thread::restart()
{
    if (!this->reset()) { return false; }
    this->start();
    return true;
}

bool omni::sync::thread::restart(omni::sync::thread_arg_t args)
{
    if (!this->reset()) { return false; }
    this->start(args);
    return true;
}

bool omni::sync::thread::restart(const omni::sync::parameterized_thread_start& mthd)
{
    this->bind(mthd);
    return this->restart();
}

bool omni::sync::thread::restart(const omni::sync::thread_start& mthd)
{
    this->bind(mthd);
    return this->restart();
}

bool omni::sync::thread::restart(const omni::sync::parameterized_thread_start& mthd, omni::sync::thread_arg_t args)
{
    this->bind(mthd);
    return this->restart(args);
}

omni::sync::thread_state omni::sync::thread::status() const
{
    OMNI_SAFE_THREAD_ALOCK_FW
    return this->m_state;
}

void omni::sync::thread::set_option(omni::sync::thread_option::enum_t op, omni::sync::thread_union_t val)
{
    OMNI_SAFE_THREAD_ALOCK_FW
    switch (op) {
        case omni::sync::thread_option::STACK_SIZE:
            this->m_ops.set_stack_size(val.s_val);
            break;
        case omni::sync::thread_option::AUTO_JOIN_TIMEOUT:
            {
                if (val.s_val > 0) {
                    // if timeout > 0 then auto join should be true
                    this->m_ops.set_flag(omni::sync::thread_option::AUTO_JOIN, true);
                    // auto-join over-rides detach (since detach is default)
                    this->m_ops.set_flag(omni::sync::thread_option::DETACH_ON_DESTROY, false);
                }
                this->m_ops.set_auto_join_timeout(val.s_val);
            } break;
        case omni::sync::thread_option::ALLOW_THREAD_REUSE:
            this->m_ops.set_flag(omni::sync::thread_option::ALLOW_THREAD_REUSE, val.b_val);
            break;
        case omni::sync::thread_option::AUTO_JOIN:
            {
                if (val.b_val) {
                    // auto-join over-rides detach
                    this->m_ops.set_flag(omni::sync::thread_option::DETACH_ON_DESTROY, false);
                }
                this->m_ops.set_flag(omni::sync::thread_option::AUTO_JOIN, val.b_val);
            } break;
        case omni::sync::thread_option::DETACH_ON_DESTROY:
            {
                if (val.b_val) {
                    // if the user sets detach, then auto-join should be false
                    this->m_ops.set_flag(omni::sync::thread_option::AUTO_JOIN, false);
                }
                this->m_ops.set_flag(omni::sync::thread_option::DETACH_ON_DESTROY, val.b_val);
            } break;
        case omni::sync::thread_option::ABORT_ON_DESTROY:
            {
                if (val.b_val) {
                    // abort over-rides detach
                    this->m_ops.set_flag(omni::sync::thread_option::DETACH_ON_DESTROY, false);
                    this->m_ops.set_flag(omni::sync::thread_option::KILL_ON_DESTROY, false);
                }
                this->m_ops.set_flag(omni::sync::thread_option::ABORT_ON_DESTROY, val.b_val);
            } break;
        case omni::sync::thread_option::KILL_ON_DESTROY:
            {
                if (val.b_val) {
                    this->m_ops.set_flag(omni::sync::thread_option::DETACH_ON_DESTROY, false);
                    this->m_ops.set_flag(omni::sync::thread_option::ABORT_ON_DESTROY, false);
                }
                this->m_ops.set_flag(omni::sync::thread_option::KILL_ON_DESTROY, val.b_val);
            } break;
        case omni::sync::thread_option::DETACH_ON_ASSIGN:
            this->m_ops.set_flag(omni::sync::thread_option::DETACH_ON_ASSIGN, val.b_val);
            break;
        case omni::sync::thread_option::ABORT_ON_ASSIGN:
            {
                if (val.b_val) {
                    this->m_ops.set_flag(omni::sync::thread_option::DETACH_ON_ASSIGN, false);
                }
                this->m_ops.set_flag(omni::sync::thread_option::ABORT_ON_ASSIGN, val.b_val);
            } break;
        case omni::sync::thread_option::KILL_ON_ASSIGN:
            {
                if (val.b_val) {
                    this->m_ops.set_flag(omni::sync::thread_option::ABORT_ON_ASSIGN, false);
                    this->m_ops.set_flag(omni::sync::thread_option::DETACH_ON_ASSIGN, false);
                }
                this->m_ops.set_flag(omni::sync::thread_option::KILL_ON_ASSIGN, val.b_val);
            } break;
        case omni::sync::thread_option::NONE:
        default:
            OMNI_ERRV_FW("invalid option: ", op, omni::exceptions::invalid_thread_option(static_cast<std::size_t>(op)))
            break;
    }
}

void omni::sync::thread::set_options(unsigned char op, bool val)
{
    OMNI_SAFE_THREAD_ALOCK_FW
    bool valid_op = false;
    if (OMNI_VAL_HAS_FLAG_BIT(op, omni::sync::thread_option::ALLOW_THREAD_REUSE)) {
        this->m_ops.set_flag(omni::sync::thread_option::ALLOW_THREAD_REUSE, val);
        valid_op = true;
    }
    if (OMNI_VAL_HAS_FLAG_BIT(op, omni::sync::thread_option::AUTO_JOIN)) {
        this->m_ops.set_flag(omni::sync::thread_option::AUTO_JOIN, val);
        valid_op = true;
    }
    if (OMNI_VAL_HAS_FLAG_BIT(op, omni::sync::thread_option::DETACH_ON_DESTROY)) {
        this->m_ops.set_flag(omni::sync::thread_option::DETACH_ON_DESTROY, val);
        valid_op = true;
    }
    if (OMNI_VAL_HAS_FLAG_BIT(op, omni::sync::thread_option::ABORT_ON_DESTROY)) {
        this->m_ops.set_flag(omni::sync::thread_option::ABORT_ON_DESTROY, val);
        valid_op = true;
    }
    if (OMNI_VAL_HAS_FLAG_BIT(op, omni::sync::thread_option::KILL_ON_DESTROY)) {
        this->m_ops.set_flag(omni::sync::thread_option::KILL_ON_DESTROY, val);
        valid_op = true;
    }
    if (OMNI_VAL_HAS_FLAG_BIT(op, omni::sync::thread_option::DETACH_ON_ASSIGN)) {
        this->m_ops.set_flag(omni::sync::thread_option::DETACH_ON_ASSIGN, val);
        valid_op = true;
    }
    if (OMNI_VAL_HAS_FLAG_BIT(op, omni::sync::thread_option::ABORT_ON_ASSIGN)) {
        this->m_ops.set_flag(omni::sync::thread_option::ABORT_ON_ASSIGN, val);
        valid_op = true;
    }
    if (OMNI_VAL_HAS_FLAG_BIT(op, omni::sync::thread_option::KILL_ON_ASSIGN)) {
        this->m_ops.set_flag(omni::sync::thread_option::KILL_ON_ASSIGN, val);
        valid_op = true;
    }
    if (!valid_op) {
        OMNI_ERRV_FW("invalid option: ", op, omni::exceptions::invalid_thread_option(static_cast<std::size_t>(op)))
    }
}

void omni::sync::thread::set_options(const omni::sync::thread_flags& ops)
{
    OMNI_SAFE_THREAD_ALOCK_FW
    this->m_ops = ops;
}

omni::sync::thread_t omni::sync::thread::start()
{
    return this->start(OMNI_THREAD_ARG_NULL_T);
}

omni::sync::thread_t omni::sync::thread::start(omni::sync::thread_arg_t args)
{
    OMNI_SAFE_THREAD_ALOCK_FW
    if (this->m_state != omni::sync::thread_state::UNSTARTED) {
        if (this->m_ops.allow_reuse()) {
            // thread reuse is enabled, so reset the handles
            this->_hreset(true, false);
        } else {
            OMNI_ERR_RET_FW("Can not start a thread once it has been started or if it is in an unknown state", omni::exceptions::thread_running_exception());
        }
    }
    if (this->m_mthd == OMNI_NULL) {
        // no delegate attached to this thread so we can't actually start anything
        OMNI_ERR_RET_FW(OMNI_INVALID_DELEGATE_FUNC_STR, omni::exceptions::invalid_delegate())
    }
    int perr = 0;
    std::size_t stack_size = this->m_ops.stack_size();
    omni::sync::thread_args bargs;
    this->m_args = (this->m_ispmthd ? args : OMNI_THREAD_ARG_NULL_T);
    this->m_state = omni::sync::thread_state::START_REQUESTED;
    this->m_thread = 0;
    bargs.bthread = this;
    #if defined(OMNI_OS_WIN)
        OMNI_TMPIDT_FW tmptid = 0;
        this->m_thread = OMNI_CREATE_THREAD_FW(NULL, // default security attr
                                             stack_size, // stack size
                                             &omni::sync::thread::_start, // _start(void*)
                                             static_cast<void*>(&bargs), // args
                                             0, // start now
                                             &tmptid); // thread id
        // Win32 returns !0 for a valid thread, 0 means error
        if (this->m_thread == 0) { perr = OMNI_GLE; } // error, set perr
        else { this->m_tid = static_cast<omni::sync::thread_t>(tmptid); } // success, set tid
    #else
        // if any of these fails, then thread creation should fail
        if (stack_size == 0) {
            perr = ::pthread_create(&this->m_tid, // the thread id
                                    NULL, // stack size == 0, so null attributes
                                    &omni::sync::thread::_start, // _start(void*)
                                    static_cast<void*>(&bargs)); // args
            if (perr == 0) {
                this->m_thread = this->m_tid; // copy TID to m_thread handle
            } else {
                OMNI_ERRV_FW("system create thread failed: ", perr, omni::exceptions::thread_exception("Create system thread failed: ", perr));
            }
        } else {
            pthread_attr_t attr;
            perr = ::pthread_attr_init(&attr);
            if (perr == 0) {
                perr = ::pthread_attr_setstacksize(&attr, stack_size);
                if (perr == 0) {
                    perr = ::pthread_create(&this->m_tid, // the thread id
                                            &attr, // stack size
                                            &omni::sync::thread::_start, // _start(void*)
                                            static_cast<void*>(&bargs)); // args
                    if (perr == 0) {
                        this->m_thread = this->m_tid; // copy TID to m_thread handle
                    } else {
                        OMNI_ERRV_FW("system create thread failed: ", perr, omni::exceptions::thread_exception("Create system thread failed: ", perr));
                    }
                } else {
                    OMNI_ERR_FW("could not set stack size of " << stack_size << ": " << perr, omni::exceptions::thread_exception("System error setting stack size: ", perr))
                }
                if (perr == 0) {
                    // Destroy the attributes handle
                    perr = ::pthread_attr_destroy(&attr);
                    if (perr != 0) {
                        /* this should only ever happen if 'attr' is not valid
                        but to be safe we want to alert the user since this could signal
                        other issues (we also don't want any rouge handles not being
                        destroyed, ie a memory leak) */
                        OMNI_ERRV_FW("could not destroy attributes: ", perr, omni::exceptions::thread_exception("Could not destroy attributes: ", perr));
                    }
                } else {
                    /* if we got here then there were other errors in thread creation, so
                    don't reset the perr value, just call the function */
                    ::pthread_attr_destroy(&attr);
                }
            } else {
                OMNI_ERR_FW("could not initialize thread attributes @" << &attr << ": " << perr, omni::exceptions::thread_exception("Could not initialize thread attributes: ", perr));
            }
        }
    #endif
    if (perr == 0) {
        OMNI_D4_FW("thread handle valid, waiting for thread switch");
        // valid handle so wait until the thread is actually reported as started
        bargs.swait.sleep_wait();
    } else {
        this->m_thread = 0;
        OMNI_ERRV_FW("could not create system thread: ", perr, omni::exceptions::thread_exception(perr))
    }
    OMNI_D3_FW(((this->m_tid == 0) ? "invalid" : "created") << " thread:" << this->m_tid);
    return this->m_tid;
}

void omni::sync::thread::swap(omni::sync::thread &o)
{
    if (this != &o) {
        #if defined(OMNI_SAFE_THREAD)
            this->m_mtx.lock();
            o.m_mtx.lock();
        #endif
        std::swap(this->aborted, o.aborted);
        std::swap(this->completed, o.completed);
        std::swap(this->m_args, o.m_args);
        std::swap(this->m_tid, o.m_tid);
        std::swap(this->m_thread, o.m_thread);
        std::swap(this->m_ops, o.m_ops);
        std::swap(this->m_state, o.m_state);
        #if defined(OMNI_NON_PORTABLE)
            std::swap(this->m_priority, o.m_priority);
        #endif
        std::swap(this->m_isjoined, o.m_isjoined);
        std::swap(this->m_mthd, o.m_mthd);
        std::swap(this->m_ispmthd, o.m_ispmthd);
        #if defined(OMNI_SAFE_THREAD)
            this->m_mtx.unlock();
            o.m_mtx.unlock();
        #endif
        
        // old code only here for direct reference...
        // we don't get a copy because of the thread dtor
        //omni::sync::thread tmp(o); // get a copy
        //o._set_context(*this);
        //this->_set_context(tmp);
    }
}

bool omni::sync::thread::unbind()
{
    OMNI_SAFE_THREAD_ALOCK_FW
    if ((this->_hvalid() && this->_state_running()))
    {
        /* don't check thread re-use here since it doesn't make sense here;
        the logic is that the user must explicitly detach or reset the thread before they can unbind */
        OMNI_ERR_RETV_FW("cannot detach method while thread is running", omni::exceptions::thread_running_exception(), false)
    }
    this->_chkmthd();
    return true;
}

omni::sync::thread &omni::sync::thread::operator=(const omni::sync::thread &o)
{
    if (this != &o) {
        OMNI_SAFE_THREAD_LOCK_FW
        if (this->_hvalid() && this->_state_running()) {
            if (this->m_ops.detach_on_assign()) {
                this->_hreset(true, false); // detach
            } else {
                if (this->m_ops.abort_on_assign()) {
                    this->m_state = omni::sync::thread_state::ABORT_REQUESTED;
                    omni::sync::thread::manager::instance().abort(this->m_tid);
                    OMNI_SAFE_THREAD_UNLOCK_FW
                    if (this->aborted) { this->aborted(*this); }
                    OMNI_SAFE_THREAD_LOCK_FW
                }
                if (this->m_ops.kill_on_assign()) {
                    OMNI_SAFE_THREAD_UNLOCK_FW
                    this->kill();
                    OMNI_SAFE_THREAD_LOCK_FW
                }
                // no auto_join in this context
            }
        }
        OMNI_ASSIGN_FW(o)
        this->_set_context(o);
        OMNI_SAFE_THREAD_UNLOCK_FW
    }
    return *this;
}

bool omni::sync::thread::operator==(const omni::sync::thread &o) const
{
    if (this == &o) { return true; }
    #if defined(OMNI_SAFE_THREAD)
        omni::sync::scoped_lock<omni::sync::basic_lock> am(&this->m_mtx);
        omni::sync::scoped_lock<omni::sync::basic_lock> am2(&o.m_mtx);
    #endif
    return (this->aborted == o.aborted &&
        this->completed == o.completed &&
        this->m_args == o.m_args &&
        this->m_ops == o.m_ops &&
        this->m_state == o.m_state &&
        this->m_tid == o.m_tid &&
        this->m_thread == o.m_thread &&
        this->m_isjoined == o.m_isjoined &&
        ((this->m_mthd == o.m_mthd) ||
        (((this->m_mthd != OMNI_NULL) && (o.m_mthd != OMNI_NULL)) && (this->m_ispmthd == o.m_ispmthd) &&
        (this->m_ispmthd ? (*static_cast<omni::sync::parameterized_thread_start*>(this->m_mthd) == *static_cast<omni::sync::parameterized_thread_start*>(o.m_mthd))
                         : (*static_cast<omni::sync::thread_start*>(this->m_mthd) == *static_cast<omni::sync::thread_start*>(o.m_mthd)))))
        #if defined(OMNI_NON_PORTABLE)
            && this->m_priority == o.m_priority
        #endif
        OMNI_EQUAL_FW(o)
        );
}

bool omni::sync::thread::operator!=(const omni::sync::thread &o) const
{
    return !(*this == o);
}

///////// private methods /////////

void omni::sync::thread::_chkmthd()
{
    if (this->m_mthd != OMNI_NULL) {
        if (this->m_ispmthd) {
            delete static_cast<omni::sync::parameterized_thread_start*>(this->m_mthd);
        } else {
            delete static_cast<omni::sync::thread_start*>(this->m_mthd);
        }
    }
    this->m_mthd = OMNI_NULL;
    this->m_ispmthd = false;
}

void omni::sync::thread::_close_handle(bool allow_rejoin)
{
    if (this->m_tid != 0) { omni::sync::thread::manager::instance().remove(this->m_tid); }
    this->m_state = omni::sync::thread_state::UNSTARTED;
    if (this->m_thread != 0 && !allow_rejoin) {
        // detach the handle so the OS can cleanup when it's done
        if (!this->m_isjoined) {
            OMNI_D5_FW("closing handle");
            #if defined(OMNI_OS_WIN)
                ::CloseHandle(OMNI_WIN_TOHNDL_FW(this->m_thread));
            #else
                /* if we've called pthread_join on this thread then don't detach
                it as that releases it's resources and makes it 'unjoinable' */
                ::pthread_detach(this->m_thread);
            #endif
        }
    }
    this->m_isjoined = false;
    this->m_thread = 0;
    this->m_tid = 0;
    OMNI_D5_FW("handle closed");
}

void omni::sync::thread::_hreset(bool force, bool allow_rejoin)
{
    #if defined(OMNI_NON_PORTABLE)
        this->m_priority = omni::sync::thread_priority::NORMAL;
    #endif
    if (this->m_ops.allow_reuse() || force) { this->_close_handle(allow_rejoin); }
}

bool omni::sync::thread::_hvalid() const
{
    return (this->m_thread != 0);
}

bool omni::sync::thread::_state_running() const
{
    return (this->m_state == omni::sync::thread_state::RUNNING ||
            this->m_state == omni::sync::thread_state::STOP_REQUESTED ||
            this->m_state == omni::sync::thread_state::ABORT_REQUESTED ||
            this->m_state == omni::sync::thread_state::UNKNOWN);
}

void omni::sync::thread::_state_changed(omni::sync::thread_state::enum_t nstate)
{
    OMNI_SAFE_THREAD_LOCK_FW
    omni::sync::thread_t tid = this->m_tid;
    this->m_state = nstate;
    OMNI_SAFE_THREAD_UNLOCK_FW
    switch (nstate) {
        case omni::sync::thread_state::ABORT_REQUESTED: {
            omni::sync::thread::manager::instance().abort(tid);
            if (this->aborted) { this->aborted(*this); }
        } break;
        case omni::sync::thread_state::ABORTED:
        case omni::sync::thread_state::COMPLETED:
        case omni::sync::thread_state::STOPPED:
            if (this->completed) { this->completed(*this); }
            // _hreset is called on dtor/detach or on start when thread_reuse==true
            // calling 'anything' after this statement is not guaranteed
            break;
        // here for pedant, no need to throw errors as this simply changes the 'state' of the thread enum
        case omni::sync::thread_state::START_REQUESTED: case omni::sync::thread_state::STOP_REQUESTED:
        case omni::sync::thread_state::UNSTARTED: case omni::sync::thread_state::UNKNOWN:
        case omni::sync::thread_state::RUNNING: default: break;
    }
}

void omni::sync::thread::_state_machine()
{
    // We can't check for a stop request since that is a user killing
    // this thread, and if that succeeded then we wouldn't get here
    OMNI_SAFE_THREAD_LOCK_FW
    omni::sync::thread_state::enum_t st = this->m_state.value();
    OMNI_SAFE_THREAD_UNLOCK_FW
    switch (st) {
        case omni::sync::thread_state::RUNNING:
            this->_state_changed(omni::sync::thread_state::COMPLETED);
            break;
        case omni::sync::thread_state::ABORT_REQUESTED:
            this->_state_changed(omni::sync::thread_state::ABORTED);
            break;
        case omni::sync::thread_state::ABORTED: case omni::sync::thread_state::COMPLETED:
        case omni::sync::thread_state::STOP_REQUESTED: case omni::sync::thread_state::START_REQUESTED:
        case omni::sync::thread_state::UNSTARTED: case omni::sync::thread_state::UNKNOWN:
        case omni::sync::thread_state::STOPPED:
        default:
            /* everything else is a "stopped" by default because this "state machine" function is intended to only
            handle if an abort_request came or if the thread completed on the internal thread function (_start)
            so if this "state machine" function gets any other's, it should be noted and the thread object put
            in a "stopped" state (since there's a chance this would happen on a kill) */
            OMNI_DBGE("An invalid thread state was specified for the state_machine");
            this->_state_changed(omni::sync::thread_state::STOPPED);
            break;
    }
    // don't throw an error if the pointers are different .. this is in the event a thread object is detached
}

void omni::sync::thread::_set_context(const omni::sync::thread& t2)
{
    /* The point of this function to avoid a temporary; if a temp omni::sync::thread is created it
    will then be destructed and call thread dtor (and abort/kill/etc. accordingly). Hence the need
    for this function. */
    #if defined(OMNI_SAFE_THREAD)
        this->m_mtx.lock();
        t2.m_mtx.lock();
    #endif
    this->aborted = t2.aborted;
    this->completed = t2.completed;
    this->m_args = t2.m_args;
    this->m_tid = t2.m_tid;
    this->m_thread = t2.m_thread;
    this->m_ops = t2.m_ops;
    this->m_state = t2.m_state;
    #if defined(OMNI_NON_PORTABLE)
        this->m_priority = t2.m_priority;
    #endif
    this->m_isjoined = t2.m_isjoined;    
    this->_chkmthd();
    if (t2.m_mthd != OMNI_NULL) {
        if (t2.m_ispmthd) {
            this->m_mthd = new omni::sync::thread_start(*(static_cast<omni::sync::thread_start*>(t2.m_mthd)));
        } else {
            this->m_mthd = new omni::sync::parameterized_thread_start(*(static_cast<omni::sync::parameterized_thread_start*>(t2.m_mthd)));
            this->m_ispmthd = true;
        }
    }
    #if defined(OMNI_SAFE_THREAD)
        t2.m_mtx.unlock();
        this->m_mtx.unlock();
    #endif
}

///////// non portable methods /////////

#if defined(OMNI_NON_PORTABLE)

void omni::sync::thread::_set_prio()
{
    int pri = static_cast<int>(this->m_priority);
    OMNI_DV4_FW("changing priority to ", pri);
    /* we don't throw an error if we can't set the thread priority since the
    OS could decide not to do it any ways or the system may not support it */
    #if defined(OMNI_OS_WIN)
        if (::SetThreadPriority(OMNI_WIN_TOHNDL_FW(this->m_thread), pri) == 0) {
            OMNI_DBGE(OMNI_ERR_SET_PRI_STR << ": " << OMNI_GLE)
        }
    #else
        int sched = 0;
        struct sched_param param;
        std::memset(&param, 0, sizeof(sched_param));
        if (::pthread_getschedparam(this->m_thread, &sched, &param) == 0) {
            int min = ::sched_get_priority_min(sched);
            int max = ::sched_get_priority_max(sched);
            if (pri < min) { pri = min; }
            if (pri > max) { pri = max; }
            /* if max < min, there are system errors, however, if min == max
            chances are the scheduling priority is OS dependant (i.e. min=0, max=0 for SCHED_OTHER)
            thus, the OS will decide the scheduling priority for the thread
            regardless if we set the thread priority. */
            if (max > min) {
                int skip = (max - min) / omni::sync::thread_priority::COUNT();
                /* getting a 'normalized' value that's representative of
                this->m_priority according to the system scheduling policy */
                param.sched_priority = (min + ((pri+2) * (skip+1))) + (skip / 2);
                if (::pthread_setschedparam(this->m_thread, sched, &param) != 0) {
                    OMNI_DBGE(OMNI_ERR_SET_PRI_STR << ": " << OMNI_GLE)
                }
            }
            #if defined(OMNI_SHOW_DEBUG_ERR)
            else { OMNI_DBGEV(OMNI_ERR_SET_PRI_STR, ": sched prio max <= min") }
            #endif
        }
        #if defined(OMNI_SHOW_DEBUG_ERR)
        else { OMNI_DBGE(OMNI_ERR_SET_PRI_STR << ": " << OMNI_GLE) }
        #endif
    #endif
}

omni::sync::thread_priority omni::sync::thread::priority() const
{
    OMNI_SAFE_THREAD_ALOCK_FW
    return this->m_priority;
}

void omni::sync::thread::set_priority(omni::sync::thread_priority::enum_t p)
{
    /*
        DEV_NOTE: Thread scheduling is system dependent, this means that even
        though you can ask the scheduler to set a threads priority, it won't always listen.
        Some systems implement a more robust scheduler; OpenBSD for instance implements
        a type of round robin scheduler that schedules threads according to set priority.
        Others implement a load based scheduler; Ubuntu (and quite a few other Linux variants)
        for example implement an approach where by a thread is scheduled on it's priority
        only when the CPU is under heavy stress, otherwise all threads get equal priority.
        
        As such, setting the thread priority is not guaranteed (per MSDN and the POSIX
        documentation), which means while we can give this functionality to you in a
        platform independent manor, be aware that thread priorities are in fact
        system dependent and even the systems themselves state they cannot guarantee
        setting the priority will mean anything.
        
        To a degree this makes sense in the fact that allowing a user land thread to
        have a higher priority than a kernel thread could be potentially harmful, so
        again be aware of this non guaranteed function.
    */
    
    int pri = static_cast<int>(p);
    if (pri < omni::sync::thread_priority::LOWEST) { pri = omni::sync::thread_priority::IDLE; }
    if (pri > omni::sync::thread_priority::HIGHEST) { pri = omni::sync::thread_priority::REAL_TIME; }
    if ((pri < omni::sync::thread_priority::LOWEST && pri != omni::sync::thread_priority::IDLE) ||
        (pri > omni::sync::thread_priority::HIGHEST && pri != omni::sync::thread_priority::REAL_TIME))
    {
        // invalid_priority
        OMNI_ERRV_RET_FW("invalid priority: ", pri, omni::exceptions::invalid_thread_option(static_cast<size_t>(pri)))
    }
    OMNI_SAFE_THREAD_LOCK_FW
    // if we're not running, just set the priority til next time
    this->m_priority = pri;
    OMNI_SAFE_THREAD_UNLOCK_FW
    if (this->is_alive()) {
        OMNI_SAFE_THREAD_ALOCK_FW
        // we can only set the priority if the thread is running and handle is valid
        if (!this->_hvalid()) {
            OMNI_ERR_FW(OMNI_INVALID_THREAD_HANDLE_STR, omni::exceptions::invalid_thread_handle())
        } else {
            this->_set_prio();
        }
    }
}

#endif

///////// omni::sync::thread (end) /////////