STORAGE* storage_create(const STORAGE_DEVICE_DESCRIPTOR *device_descriptor, STORAGE_DRIVER_CB *driver_cb, void *driver_param) { STORAGE* storage = (STORAGE*)sys_alloc(sizeof(STORAGE)); if (storage) { storage->rx_event = event_create(); storage->tx_event = event_create(); storage->device_descriptor = device_descriptor; storage->driver_cb = driver_cb; storage->driver_param = driver_param; storage->media_descriptor = NULL; storage->host_cb = NULL; storage->host_io_cb = NULL; storage->host_io_param = NULL; storage->reading = false; storage->writing = false; storage->queue = NULL; storage->block_size = 0; } else error(ERROR_MEM_OUT_OF_SYSTEM_MEMORY, "STORAGE"); return storage; }
struct session * _new_session() { struct session * self = NULL; self = calloc( 1, sizeof(struct session) ); if ( self == NULL ) { return NULL; } // 初始化网络事件 self->evread = event_create(); self->evwrite = event_create(); self->evkeepalive = event_create(); if ( self->evkeepalive == NULL || self->evread == NULL || self->evwrite == NULL ) { _del_session( self ); return NULL; } // 初始化发送队列 if ( QUEUE_INIT(sendqueue)(&self->sendqueue, DEFAULT_SENDQUEUE_SIZE) != 0 ) { _del_session( self ); return NULL; } return self; }
PJ_DEF(int) jitter_buffer_create(Jitter_Buffer ** jitter_buffer, pj_pool_t *pool, int max_number_of_frames, NACK_MODE nack_mode, int low_rtt_threshold_ms, int high_rtt_threshold_ms) { pj_assert(low_rtt_threshold_ms <= high_rtt_threshold_ms); //alloc jitter buffer Jitter_Buffer *jitter_buffer_internal = (Jitter_Buffer*)pj_pool_zalloc(pool, sizeof(Jitter_Buffer)); //init list alloc list_alloc_init(&jitter_buffer_internal->frame_alloc, pool); list_alloc_init(&jitter_buffer_internal->packet_alloc, pool); //init frame list, don't call frame_buffer_init, //since the header is not used as a real frame pj_list_init(&jitter_buffer_internal->frameList); pj_list_init(&jitter_buffer_internal->decodingFrameList); //init frame number jitter_buffer_internal->max_number_of_frames = max_number_of_frames < MIN_NUM_OF_FRAMES? MIN_NUM_OF_FRAMES : max_number_of_frames; jitter_buffer_internal->number_of_frames = 0; //init decode state decode_state_init(&jitter_buffer_internal->decode_state); //init jitter estimator jitter_estimator_init(&jitter_buffer_internal->jitter_estimator); //init inter_frame_delay inter_frame_delay_init(&jitter_buffer_internal->inter_frame_delay); //init rtt jitter_buffer_internal->rttMs = DEFAULT_RTT_MS; //init nack if(high_rtt_threshold_ms != -1) jitter_buffer_internal->rttMs = 0; jitter_buffer_internal->nack_mode = nack_mode; jitter_buffer_internal->low_rtt_threshold_ms = low_rtt_threshold_ms; jitter_buffer_internal->high_rtt_threshold_ms = high_rtt_threshold_ms; jitter_buffer_internal->nack_seq_num = 0; //init event if(event_create(&jitter_buffer_internal->frame_event) != 0) { return -1; } if(event_create(&jitter_buffer_internal->packet_event) != 0) return -1; //not running jitter_buffer_internal->running = PJ_FALSE; //first packet jitter_buffer_internal->first_packet = PJ_FALSE; //the first frame must be key frame jitter_buffer_internal->waiting_for_key_frame = PJ_TRUE; //waiting for completed frame jitter_buffer_internal->waiting_for_completed_frame.timestamp = 0; jitter_buffer_internal->waiting_for_completed_frame.frame_size = 0; jitter_buffer_internal->waiting_for_completed_frame.latest_packet_timestamp = -1; //init mutex if(pj_mutex_create_simple(pool, NULL, &jitter_buffer_internal->jb_mutex) != PJ_SUCCESS) return -1; //ret *jitter_buffer = jitter_buffer_internal; return 0; }
static void bsdtcp_fn_connect( void *cookie, security_handle_t *security_handle, security_status_t status) { struct sec_handle *rh = cookie; int result; if (status == S_OK) { int so_errno; socklen_t error_len = sizeof(so_errno); if (getsockopt(rh->rc->write, SOL_SOCKET, SO_ERROR, &so_errno, &error_len) == -1) { status = S_ERROR; } else if (rh->next_res && so_errno == ECONNREFUSED) { status = S_ERROR; } } switch (status) { case S_TIMEOUT: case S_ERROR: if (rh->next_res) { while (rh->next_res) { result = runbsdtcp(rh, rh->src_ip, rh->port); if (result >= 0) { rh->rc->refcnt++; rh->rs->rc->ev_write = event_create( (event_id_t)(rh->rs->rc->write), EV_WRITEFD, sec_connect_callback, rh); rh->ev_timeout = event_create(CONNECT_TIMEOUT, EV_TIME, sec_connect_timeout, rh); event_activate(rh->rs->rc->ev_write); event_activate(rh->ev_timeout); return; } } } // pass through case S_OK: if (rh->res) freeaddrinfo(rh->res); rh->res = NULL; rh->next_res = NULL; rh->src_ip = NULL; rh->port = 0; rh->connect_callback(rh->connect_arg, security_handle, status); break; default: assert(0); break; } }
static void run_task_test(void) { tasks_init(); events_init(); sleep(2); /* wait for both threads to run */ tasks_add(task_create(test, NULL)); events_add(event_create(2, config_parse_event, (void *)"config_test")); events_add(event_create(2, test, NULL)); sleep(5); events_add(event_create(3, test, NULL)); events_stop(); tasks_stop(); }
void fiber_io_check(void) { if (__thread_fiber != NULL) return; acl_assert(acl_pthread_once(&__once_control, thread_init) == 0); __maxfd = acl_open_limit(0); if (__maxfd <= 0) __maxfd = MAXFD; __thread_fiber = (FIBER_TLS *) acl_mymalloc(sizeof(FIBER_TLS)); __thread_fiber->event = event_create(__maxfd); __thread_fiber->io_fibers = (ACL_FIBER **) acl_mycalloc(__maxfd, sizeof(ACL_FIBER *)); __thread_fiber->ev_fiber = acl_fiber_create(fiber_io_loop, __thread_fiber->event, STACK_SIZE); __thread_fiber->io_count = 0; __thread_fiber->nsleeping = 0; __thread_fiber->io_stop = 0; acl_ring_init(&__thread_fiber->ev_timer); if ((unsigned long) acl_pthread_self() == acl_main_thread_self()) { __main_fiber = __thread_fiber; atexit(fiber_io_main_free); } else if (acl_pthread_setspecific(__fiber_key, __thread_fiber) != 0) acl_msg_fatal("acl_pthread_setspecific error!"); }
celix_status_t serviceDependency_removedService(void *_ptr, service_reference_pt reference, void *service) { celix_status_t status = CELIX_SUCCESS; bundle_context_pt context = NULL; bundle_pt bundle = NULL; dm_event_pt event = NULL; dm_service_dependency_pt dependency = _ptr; if (!dependency || !reference || !service) { status = CELIX_ILLEGAL_ARGUMENT; } if (status == CELIX_SUCCESS) { status = component_getBundleContext(dependency->component, &context); if (!context) { status = CELIX_BUNDLE_EXCEPTION; } } if (status == CELIX_SUCCESS) { status = bundleContext_getBundle(context, &bundle); if (!bundle) { status = CELIX_BUNDLE_EXCEPTION; } } if (status == CELIX_SUCCESS) { status = event_create(DM_EVENT_REMOVED, bundle, context, reference, service, &event); } if (status == CELIX_SUCCESS) { component_handleEvent(dependency->component, dependency, event); } return status; }
/* * Début de traitement d'une PDU */ void srvGen_startService(struct srvGen_t * srv, struct PDU_t * pdu) { struct event_t * event; double date ; assert(pdu != NULL); // Si le destinataire n'a pas récupéré la précédente, trop tard ! if (srv->currentPDU != NULL) { PDU_free(srv->currentPDU); } srv->srvState = srvStateBusy; srv->serviceStartTime = motSim_getCurrentTime(); srv->currentPDU = pdu; //Déterminer une date de fin en fonction du temps de traitement if (srv->serviceTime == serviceTimeProp){ date = motSim_getCurrentTime() + PDU_size(pdu) * srv->serviceTimeParameter; } else { assert(srv->dateGenerator); date = dateGenerator_nextDate(srv->dateGenerator); } printf_debug(DEBUG_SRV, " PDU %d from %6.3f to %6.3f\n", PDU_id(pdu), motSim_getCurrentTime(), date); // On crée un événement event = event_create((eventAction_t)srvGen_terminateProcess, srv); // On ajoute cet événement au simulateur pour cette date motSim_scheduleEvent(event, date); }
CWarMap::CWarMap(long lMapIndex, const TGuildWarInfo & r_info, TWarMapInfo * pkWarMapInfo, DWORD dwGuildID1, DWORD dwGuildID2) { m_kMapInfo = *pkWarMapInfo; m_kMapInfo.lMapIndex = lMapIndex; memcpy(&m_WarInfo, &r_info, sizeof(TGuildWarInfo)); m_TeamData[0].Initialize(); m_TeamData[0].dwID = dwGuildID1; m_TeamData[0].pkGuild = CGuildManager::instance().TouchGuild(dwGuildID1); m_TeamData[1].Initialize(); m_TeamData[1].dwID = dwGuildID2; m_TeamData[1].pkGuild = CGuildManager::instance().TouchGuild(dwGuildID2); m_iObserverCount = 0; war_map_info* info = AllocEventInfo<war_map_info>(); info->pWarMap = this; SetBeginEvent(event_create(war_begin_event, info, PASSES_PER_SEC(60))); m_pkEndEvent = NULL; m_pkTimeoutEvent = NULL; m_pkResetFlagEvent = NULL; m_bTimeout = false; m_dwStartTime = get_dword_time(); m_bEnded = false; if (GetType() == WAR_MAP_TYPE_FLAG) { AddFlagBase(0); AddFlagBase(1); AddFlag(0); AddFlag(1); } }
void CWarMap::CheckWarEnd() { if (m_bEnded) return; if (m_TeamData[0].iMemberCount == 0 || m_TeamData[1].iMemberCount == 0) { if (m_bTimeout) return; if (m_pkTimeoutEvent) return; Notice(LC_TEXT("길드전에 참가한 상대방 길드원이 아무도 없습니다.")); Notice(LC_TEXT("1분 이내에 아무도 접속하지 않으면 길드전이 자동 종료됩니다.")); sys_log(0, "CheckWarEnd: Timeout begin %u vs %u", m_TeamData[0].dwID, m_TeamData[1].dwID); war_map_info* info = AllocEventInfo<war_map_info>(); info->pWarMap = this; SetTimeoutEvent(event_create(war_timeout_event, info, PASSES_PER_SEC(60))); } else CheckScore(); }
/** * @brief Parses the actual individual event nodes. * * @param parent Parent node to parse. * @return 0 on success. */ static int events_parseActive( xmlNodePtr parent ) { char *buf; unsigned int id; int data; xmlNodePtr node, cur; Event_t *ev; node = parent->xmlChildrenNode; do { if (!xml_isNode(node,"event")) continue; xmlr_attr(node,"name",buf); if (buf==NULL) { WARN("Event has missing 'name' attribute, skipping."); continue; } data = event_dataID( buf ); if (data < 0) { WARN("Event in save has name '%s' but event data not found matching name. Skipping.", buf); free(buf); continue; } free(buf); xmlr_attr(node,"id",buf); if (buf==NULL) { WARN("Event with data '%s' has missing 'id' attribute, skipping.", event_dataName(data)); continue; } id = atoi(buf); free(buf); if (id==0) { WARN("Event with data '%s' has invalid 'id' attribute, skipping.", event_dataName(data)); continue; } /* Create the event. */ event_create( data, &id ); ev = event_get( id ); if (ev == NULL) { WARN("Event with data '%s' was not created, skipping.", event_dataName(data)); continue; } ev->save = 1; /* Should save by default again. */ /* Get the data. */ cur = node->xmlChildrenNode; do { if (xml_isNode(cur,"lua")) nxml_unpersistLua( ev->L, cur ); } while (xml_nextNode(cur)); /* Claims. */ if (xml_isNode(node,"claims")) ev->claims = claim_xmlLoad( node ); } while (xml_nextNode(node)); return 0; }
struct acceptor * acceptor_create( const char * host, uint16_t port ) { struct acceptor * a = NULL; a = (struct acceptor *)malloc( sizeof(struct acceptor) ); if ( a ) { a->holding = 0; a->socketfd = 0; a->ev_accept = NULL; pthread_mutex_init( &(a->lock), NULL ); a->socketfd = tcp_listen( host, port ); if ( a->socketfd < 0 ) { acceptor_destroy( a ); return NULL; } set_fd_nonblock( a->socketfd ); a->ev_accept = event_create(); if ( a->ev_accept == NULL ) { acceptor_destroy( a ); return NULL; } } return a; }
void accept_new_session( int32_t fd, int16_t ev, void * arg ) { evsets_t coreset = ( evsets_t )arg; if ( ev & EV_READ ) { char dsthost[20]; uint16_t dstport = 0; int32_t newfd = tcp_accept( fd, dsthost, &dstport ); if ( newfd > 0 ) { set_non_block( newfd ); event_t event = event_create(); if ( event == NULL ) { printf( "accept new fd failed .\n" ); return; } event_set( event, newfd, EV_READ|EV_PERSIST ); event_set_callback( event, process_message, event ); evsets_add( coreset, event, 0 ); } } }
// ЅГ°Ј ИДєТБ¦ // timer_based_on_wear_expire_event јіён ВьБ¶ void CItem::StartTimerBasedOnWearExpireEvent() { if (m_pkTimerBasedOnWearExpireEvent) return; //±в°ЈБ¦ ѕЖАМЕЫАП °жїм ЅГ°ЈБ¦ ѕЖАМЕЫАє µїАЫЗПБц ѕКґВґЩ if (IsRealTimeItem()) return; if (-1 == GetProto()->cLimitTimerBasedOnWearIndex) return; int iSec = GetSocket(0); // іІАє ЅГ°ЈА» єРґЬА§·О Іч±в А§ЗШ... if (0 != iSec) { iSec %= 60; if (0 == iSec) iSec = 60; } item_event_info* info = AllocEventInfo<item_event_info>(); info->item = this; SetTimerBasedOnWearExpireEvent(event_create(timer_based_on_wear_expire_event, info, PASSES_PER_SEC(iSec))); }
/* * subtracts amount of hitpoints from ch's current and starts points event */ void alter_hit(struct char_data *ch, int amount) { struct regen_event_obj *regen; long time; int gain; GET_HIT(ch) = MIN(GET_HIT(ch) - amount, GET_MAX_HIT(ch)); if (GET_HIT(ch) <= HIT_INCAP||IS_AFFECTED(ch,AFF_TRAMORTITO)) return; if (PLR_FLAGGED(ch, PLR_FANTASMA) && amount > 0) return; if (GET_HIT(ch) < GET_MAX_HIT(ch) && !GET_POINTS_EVENT(ch, REGEN_HIT)) { CREATE(regen, struct regen_event_obj, 1); regen->ch = ch; regen->type = REGEN_HIT; gain = hit_gain(ch); time = PULSES_PER_MUD_HOUR / (gain ? gain : 1); GET_POINTS_EVENT(ch, REGEN_HIT) = event_create(points_event, regen, time); if (amount >= 0) { /* * if the character gained hp, update position and * restart mana and move regeneration if needed. */ update_pos(ch); alter_mana(ch, 0); alter_move(ch, 0); } }
// ½Ã°£ ÈĺÒÁ¦ // timer_based_on_wear_expire_event ¼³¸í ÂüÁ¶ void CItem::StartTimerBasedOnWearExpireEvent() { if (m_pkTimerBasedOnWearExpireEvent) return; //±â°£Á¦ ¾ÆÀÌÅÛÀÏ °æ¿ì ½Ã°£Á¦ ¾ÆÀÌÅÛÀº µ¿ÀÛÇÏÁö ¾Ê´Â´Ù if (IsRealTimeItem()) return; if (-1 == GetProto()->cLimitTimerBasedOnWearIndex) return; int iSec = GetSocket(0); // ³²Àº ½Ã°£À» ºÐ´ÜÀ§·Î ²÷±â À§ÇØ... if (0 != iSec) { iSec %= 60; if (0 == iSec) iSec = 60; } item_event_info* info = AllocEventInfo<item_event_info>(); info->item = this; SetTimerBasedOnWearExpireEvent(event_create(timer_based_on_wear_expire_event, info, PASSES_PER_SEC(iSec))); }
void CItem::StartAccessorySocketExpireEvent() { if (!IsAccessoryForSocket()) return; if (m_pkAccessorySocketExpireEvent) return; if (GetAccessorySocketMaxGrade() == 0) return; if (GetAccessorySocketGrade() == 0) return; int iSec = GetAccessorySocketDownGradeTime(); SetAccessorySocketExpireEvent(NULL); if (iSec <= 1) iSec = 5; else iSec = MIN(iSec, 60); item_vid_event_info* info = AllocEventInfo<item_vid_event_info>(); info->item_vid = GetVID(); SetAccessorySocketExpireEvent(event_create(accessory_socket_expire_event, info, PASSES_PER_SEC(iSec))); }
/** * @brief Runs all the events matching a trigger. * * @param trigger Trigger to match. */ void events_trigger( EventTrigger_t trigger ) { int i, c; for (i=0; i<event_ndata; i++) { /* Make sure trigger matches. */ if (event_data[i].trigger != trigger) continue; /* Make sure chance is succeeded. */ if (RNGF() > event_data[i].chance) continue; /* Test uniqueness. */ if ((event_data[i].flags & EVENT_FLAG_UNIQUE) && (player_eventAlreadyDone( i ) || event_alreadyRunning(i))) continue; /* Test conditional. */ if (event_data[i].cond != NULL) { c = cond_check(event_data[i].cond); if (c<0) { WARN("Conditional for event '%s' failed to run.", event_data[i].name); continue; } else if (!c) continue; } /* Create the event. */ event_create( i ); } }
void CItem::StartUniqueExpireEvent() { if (GetType() != ITEM_UNIQUE) return; if (m_pkUniqueExpireEvent) return; //±â°£Á¦ ¾ÆÀÌÅÛÀÏ °æ¿ì ½Ã°£Á¦ ¾ÆÀÌÅÛÀº µ¿ÀÛÇÏÁö ¾Ê´Â´Ù if (IsRealTimeItem()) return; // HARD CODING if (GetVnum() == UNIQUE_ITEM_HIDE_ALIGNMENT_TITLE) m_pOwner->ShowAlignment(false); int iSec = GetSocket(ITEM_SOCKET_UNIQUE_SAVE_TIME); if (iSec == 0) iSec = 60; else iSec = MIN(iSec, 60); SetSocket(ITEM_SOCKET_UNIQUE_SAVE_TIME, 0); item_event_info* info = AllocEventInfo<item_event_info>(); info->item = this; SetUniqueExpireEvent(event_create(unique_expire_event, info, PASSES_PER_SEC(iSec))); }
void * event_create_int(event_type_t type, int sym) { event_int_t *e = event_create(type, sizeof(event_int_t)); e->val = sym; return e; }
int32_t test_operate_timer() { int32_t i = 0; evsets_t sets = NULL; event_t * events = NULL; sets = evsets_create(); events = malloc( sizeof(event_t) * NTEST ); for ( i = 0; i < NTEST; ++i ) { events[i] = event_create(); event_set_callback( events[i], ev_callback, NULL ); } test_addtimer( sets, events ); test_deltimer( sets, events ); for ( i = 0; i < NTEST; ++i ) { event_destroy( events[i] ); } free( events ); evsets_destroy( sets ); return 0; }
event_t * event_create_prop(event_type_t type, prop_t *p) { event_prop_t *e = event_create(type, sizeof(event_prop_t)); e->p = prop_ref_inc(p); e->h.e_dtor = event_prop_dtor; return &e->h; }
event_t * event_create_str(event_type_t et, const char *str) { int l = strlen(str) + 1; event_t *e = event_create(et, sizeof(event_t) + l); memcpy(e->e_payload, str, l); return e; }
event_t * event_create_str(event_type_t et, const char *str) { int l = strlen(str) + 1; event_payload_t *ep = event_create(et, sizeof(event_t) + l); memcpy(ep->payload, str, l); return &ep->h; }
void CParty::Link(LPCHARACTER pkChr) { TMemberMap::iterator it; if (pkChr->IsPC()) it = m_memberMap.find(pkChr->GetPlayerID()); else it = m_memberMap.find(pkChr->GetVID()); if (it == m_memberMap.end()) { sys_err("%s is not member of this party", pkChr->GetName()); return; } // 플레이어 파티일 경우 업데이트 이벤트 생성 if (m_bPCParty && !m_eventUpdate) { party_update_event_info* info = AllocEventInfo<party_update_event_info>(); info->pid = m_dwLeaderPID; m_eventUpdate = event_create(party_update_event, info, PASSES_PER_SEC(3)); } if (it->second.bRole == PARTY_ROLE_LEADER) m_pkChrLeader = pkChr; sys_log(2, "PARTY[%d] %s linked to party", GetLeaderPID(), pkChr->GetName()); it->second.pCharacter = pkChr; pkChr->SetParty(this); if (pkChr->IsPC()) { if (it->second.strName.empty()) { it->second.strName = pkChr->GetName(); } SendPartyJoinOneToAll(pkChr->GetPlayerID()); SendPartyJoinAllToOne(pkChr); SendPartyLinkOneToAll(pkChr); SendPartyLinkAllToOne(pkChr); SendPartyInfoAllToOne(pkChr); SendPartyInfoOneToAll(pkChr); SendParameter(pkChr); //sys_log(0, "PARTY-DUNGEON connect %p %p", this, GetDungeon()); if (GetDungeon() && GetDungeon()->GetMapIndex() == pkChr->GetMapIndex()) { pkChr->SetDungeon(GetDungeon()); } RequestSetMemberLevel(pkChr->GetPlayerID(), pkChr->GetLevel()); } }
event_t * event_create_select_track(const char *id, event_type_t type, int manual) { event_select_track_t *e = event_create(type, sizeof(event_select_track_t)); e->id = strdup(id); e->manual = manual; e->h.e_dtor = event_select_track_dtor; return &e->h; }
void event_test(void) { pthread_t threads[2]; assert(0 == event_create(&ev1)); assert(0 == event_create(&ev2)); event_signal(&ev1); event_reset(&ev1); thread_create(&threads[0], thread0, NULL); thread_create(&threads[1], thread1, NULL); thread_destroy(threads[0]); thread_destroy(threads[1]); assert(0 == event_destroy(&ev1)); assert(0 == event_destroy(&ev2)); }
void event_execute_test() { TEST_TITLE ("event_execute_test : Doit afficher un warning"); PtrEvent event = NULL; event_create (&event); event -> Execute (event); event -> Destroy (&event); }
void * event_create_int3(event_type_t type, int v1, int v2, int v3) { event_int3_t *e = event_create(type, sizeof(event_int3_t)); e->val1 = v1; e->val2 = v2; e->val3 = v3; return e; }
/* * Opens and create a THREAD item for the current/calling thread. */ THREAD * thread_open( VOID ) { #ifdef _WIN32 OPENTHREAD pOpenThread = NULL; HMODULE hKernel32 = NULL; THREAD * thread = NULL; thread = (THREAD *)malloc( sizeof( THREAD ) ); if( thread != NULL ) { memset( thread, 0, sizeof(THREAD) ); thread->id = GetCurrentThreadId(); thread->sigterm = event_create(); // Windows specific process of opening a handle to the current thread which // works on NT4 up. We only want THREAD_TERMINATE|THREAD_SUSPEND_RESUME access // for now. // First we try to use the normal OpenThread function, available on Windows 2000 and up... hKernel32 = LoadLibrary( "kernel32.dll" ); pOpenThread = (OPENTHREAD)GetProcAddress( hKernel32, "OpenThread" ); if( pOpenThread ) { thread->handle = pOpenThread( THREAD_TERMINATE|THREAD_SUSPEND_RESUME, FALSE, thread->id ); } else { NTOPENTHREAD pNtOpenThread = NULL; // If we can't use OpenThread, we try the older NtOpenThread function as found on NT4 machines. HMODULE hNtDll = LoadLibrary( "ntdll.dll" ); pNtOpenThread = (NTOPENTHREAD)GetProcAddress( hNtDll, "NtOpenThread" ); if( pNtOpenThread ) { _OBJECT_ATTRIBUTES oa = {0}; _CLIENT_ID cid = {0}; cid.UniqueThread = (PVOID)thread->id; pNtOpenThread( &thread->handle, THREAD_TERMINATE|THREAD_SUSPEND_RESUME, &oa, &cid ); } FreeLibrary( hNtDll ); } FreeLibrary( hKernel32 ); } return thread; #else /* * XXX add POSIX implementation */ return NULL; #endif }