the NetHandler is init at "void initialize_thread_for_net(EThread *thread)".
{code} 260 void 261 initialize_thread_for_net(EThread *thread) 262 { 263 new ((ink_dummy_for_new *)get_NetHandler(thread)) NetHandler(); 264 new ((ink_dummy_for_new *)get_PollCont(thread)) PollCont(thread->mutex, get_NetHandler(thread)); 265 get_NetHandler(thread)->mutex = new_ProxyMutex(); 266 PollCont *pc = get_PollCont(thread); 267 PollDescriptor *pd = pc->pollDescriptor; 268 269 thread->schedule_imm(get_NetHandler(thread)); {code} the NetHandler object is allocated from thread private data by Line 263. and its mutex is assigned by Line 265. I'm searching all the ATS code, only the UnixNetVConnection::reenable() would access enable_list and ready_list. the enable_list is atomic list. it's lock free. but any operation on ready_list should get mutex locked first. {code} 783 void 784 UnixNetVConnection::reenable(VIO *vio) 785 { 786 if (STATE_FROM_VIO(vio)->enabled) 787 return; 788 set_enabled(vio); 789 if (!thread) 790 return; 791 EThread *t = vio->mutex->thread_holding; 792 ink_assert(t == this_ethread()); 793 ink_assert(!closed); 794 if (nh->mutex->thread_holding == t) { // locked 795 if (vio == &read.vio) { 796 ep.modify(EVENTIO_READ); 797 ep.refresh(EVENTIO_READ); 798 if (read.triggered) 799 nh->read_ready_list.in_or_enqueue(this); 800 else 801 nh->read_ready_list.remove(this); 802 } else { 803 ep.modify(EVENTIO_WRITE); 804 ep.refresh(EVENTIO_WRITE); 805 if (write.triggered) 806 nh->write_ready_list.in_or_enqueue(this); 807 else 808 nh->write_ready_list.remove(this); 809 } 810 } else { // non-locked 811 MUTEX_TRY_LOCK(lock, nh->mutex, t); // try lock 812 if (!lock.is_locked()) { 813 if (vio == &read.vio) { 814 if (!read.in_enabled_list) { 815 read.in_enabled_list = 1; 816 nh->read_enable_list.push(this); 817 } 818 } else { 819 if (!write.in_enabled_list) { 820 write.in_enabled_list = 1; 821 nh->write_enable_list.push(this); 822 } 823 } 824 if (nh->trigger_event && nh->trigger_event->ethread->signal_hook) 825 nh->trigger_event->ethread->signal_hook(nh->trigger_event->ethread); 826 } else { // locked 827 if (vio == &read.vio) { 828 ep.modify(EVENTIO_READ); 829 ep.refresh(EVENTIO_READ); 830 if (read.triggered) 831 nh->read_ready_list.in_or_enqueue(this); 832 else 833 nh->read_ready_list.remove(this); 834 } else { 835 ep.modify(EVENTIO_WRITE); 836 ep.refresh(EVENTIO_WRITE); 837 if (write.triggered) 838 nh->write_ready_list.in_or_enqueue(this); 839 else 840 nh->write_ready_list.remove(this); 841 } 842 } 843 } 844 } {code} these Lines from 795 to 890 and these Lines from 827 to 841 are totally same. what's the value of Lines from 794 to 810 ? why not do "get_NetHandler(thread)->mutex = thread->mutex;" ? the reenable() could be simple and clear if set nh->mutex to thread-mutex: {code} 783 void 784 UnixNetVConnection::reenable(VIO *vio) 785 { 786 if (STATE_FROM_VIO(vio)->enabled) 787 return; 788 set_enabled(vio); 789 if (!thread) 790 return; 791 EThread *t = vio->mutex->thread_holding; 792 ink_assert(t == this_ethread()); 793 ink_assert(!closed); 811 MUTEX_TRY_LOCK(lock, nh->mutex, t); // try lock 812 if (!lock.is_locked()) { 813 if (vio == &read.vio) { 814 if (!read.in_enabled_list) { 815 read.in_enabled_list = 1; 816 nh->read_enable_list.push(this); 817 } 818 } else { 819 if (!write.in_enabled_list) { 820 write.in_enabled_list = 1; 821 nh->write_enable_list.push(this); 822 } 823 } 824 if (nh->trigger_event && nh->trigger_event->ethread->signal_hook) 825 nh->trigger_event->ethread->signal_hook(nh->trigger_event->ethread); 826 } else { // locked 827 if (vio == &read.vio) { 828 ep.modify(EVENTIO_READ); 829 ep.refresh(EVENTIO_READ); 830 if (read.triggered) 831 nh->read_ready_list.in_or_enqueue(this); 832 else 833 nh->read_ready_list.remove(this); 834 } else { 835 ep.modify(EVENTIO_WRITE); 836 ep.refresh(EVENTIO_WRITE); 837 if (write.triggered) 838 nh->write_ready_list.in_or_enqueue(this); 839 else 840 nh->write_ready_list.remove(this); 841 } 842 } 844 } {code} Thanks B/R Oknet Xu