mirror of
https://github.com/Mathewnd/Astral.git
synced 2026-11-01 15:08:21 +00:00
@@ -15,7 +15,8 @@ typedef struct _dpc_t {
|
|||||||
dpcarg_t arg;
|
dpcarg_t arg;
|
||||||
} dpc_t;
|
} dpc_t;
|
||||||
|
|
||||||
void dpc_enqueue(dpc_t *dpc, dpcfn_t, dpcarg_t);
|
void dpc_prepare(dpc_t *dpc, dpcfn_t fn);
|
||||||
|
void dpc_enqueue(dpc_t *dpc, dpcarg_t arg);
|
||||||
void dpc_dequeue(dpc_t *dpc);
|
void dpc_dequeue(dpc_t *dpc);
|
||||||
void dpc_init();
|
void dpc_init();
|
||||||
|
|
||||||
|
|||||||
@@ -11,9 +11,8 @@ typedef struct timerentry_t {
|
|||||||
struct timerentry_t *next;
|
struct timerentry_t *next;
|
||||||
time_t absolutetick;
|
time_t absolutetick;
|
||||||
time_t repeatus;
|
time_t repeatus;
|
||||||
dpcfn_t fn;
|
|
||||||
dpcarg_t arg;
|
|
||||||
dpc_t dpc;
|
dpc_t dpc;
|
||||||
|
dpcarg_t arg;
|
||||||
bool fired;
|
bool fired;
|
||||||
} timerentry_t;
|
} timerentry_t;
|
||||||
|
|
||||||
|
|||||||
@@ -204,7 +204,7 @@ void ahci_dpc(context_t *, dpcarg_t arg) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// notify waiters about command completion
|
// notify waiters about command completion
|
||||||
while (port_data->waiters[port_data->command_waiting] &&
|
while (port_data->waiters[port_data->command_waiting] &&
|
||||||
(port_data->ahci->ports[port].ci & (1 << port_data->command_waiting)) == 0) {
|
(port_data->ahci->ports[port].ci & (1 << port_data->command_waiting)) == 0) {
|
||||||
thread_t *thread = port_data->waiters[port_data->command_waiting];
|
thread_t *thread = port_data->waiters[port_data->command_waiting];
|
||||||
port_data->waiters[port_data->command_waiting] = NULL;
|
port_data->waiters[port_data->command_waiting] = NULL;
|
||||||
@@ -230,7 +230,7 @@ void ahci_isr(isr_t *isr, context_t *) {
|
|||||||
if (ahci->port_data[i] == NULL)
|
if (ahci->port_data[i] == NULL)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
dpc_enqueue(&ahci->port_data[i]->dpc, ahci_dpc, ahci->port_data[i]);
|
dpc_enqueue(&ahci->port_data[i]->dpc, ahci->port_data[i]);
|
||||||
|
|
||||||
ports_pending &= ~(1 << i);
|
ports_pending &= ~(1 << i);
|
||||||
ahci->ports[i].is = ahci->ports[i].is;
|
ahci->ports[i].is = ahci->ports[i].is;
|
||||||
@@ -413,7 +413,7 @@ static void init_port(ahci_t *ahci, int port) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
ahci->port_data[port]->sector_count = (uint64_t)identify->lba48_size[0] | ((uint64_t)identify->lba48_size[1] << 16) |
|
ahci->port_data[port]->sector_count = (uint64_t)identify->lba48_size[0] | ((uint64_t)identify->lba48_size[1] << 16) |
|
||||||
((uint64_t)identify->lba48_size[2] << 32) | ((uint64_t)identify->lba48_size[3] << 48);
|
((uint64_t)identify->lba48_size[2] << 32) | ((uint64_t)identify->lba48_size[3] << 48);
|
||||||
|
|
||||||
printf("ahci%dp%d: ATA drive with %lu sectors\n", ahci->id, port, ahci->port_data[port]->sector_count);
|
printf("ahci%dp%d: ATA drive with %lu sectors\n", ahci->id, port, ahci->port_data[port]->sector_count);
|
||||||
@@ -549,7 +549,6 @@ static void init_controller(pcienum_t *pci_enum) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// program command list base
|
// program command list base
|
||||||
void *cmd_ptr = (void *)((uintptr_t)command_slot_mem + command_slot_offset);
|
void *cmd_ptr = (void *)((uintptr_t)command_slot_mem + command_slot_offset);
|
||||||
memset(MAKE_HHDM(cmd_ptr), 0, 1024);
|
memset(MAKE_HHDM(cmd_ptr), 0, 1024);
|
||||||
@@ -609,6 +608,7 @@ static void init_controller(pcienum_t *pci_enum) {
|
|||||||
port_data->command_list = MAKE_HHDM(cmd_ptr);
|
port_data->command_list = MAKE_HHDM(cmd_ptr);
|
||||||
SPINLOCK_INIT(port_data->command_lock);
|
SPINLOCK_INIT(port_data->command_lock);
|
||||||
SEMAPHORE_INIT(&port_data->command_semaphore, ahci->command_slot_count);
|
SEMAPHORE_INIT(&port_data->command_semaphore, ahci->command_slot_count);
|
||||||
|
dpc_prepare(&port_data->dpc, ahci_dpc);
|
||||||
|
|
||||||
ahci->port_data[i] = port_data;
|
ahci->port_data[i] = port_data;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -299,7 +299,7 @@ static void nvme_dpc(context_t *, dpcarg_t arg) {
|
|||||||
|
|
||||||
static void nvme_irq(isr_t *isr, context_t *context) {
|
static void nvme_irq(isr_t *isr, context_t *context) {
|
||||||
queuepair_t *pair = isr->priv;
|
queuepair_t *pair = isr->priv;
|
||||||
dpc_enqueue(&pair->dpc, nvme_dpc, pair);
|
dpc_enqueue(&pair->dpc, pair);
|
||||||
}
|
}
|
||||||
|
|
||||||
static isr_t *msixnewisrforqueue(queuepair_t *queuepair) {
|
static isr_t *msixnewisrforqueue(queuepair_t *queuepair) {
|
||||||
@@ -458,6 +458,7 @@ static int createiosubqueue(nvmecontroller_t *controller, queuedesc_t *desc, siz
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void newioqueuepair(nvmecontroller_t *controller, queuepair_t *pair, int id) {
|
static void newioqueuepair(nvmecontroller_t *controller, queuepair_t *pair, int id) {
|
||||||
|
dpc_prepare(&pair->dpc, nvme_dpc);
|
||||||
__assert(createiocompqueue(controller, &pair->completion, QUEUEPAIR_ENTRY_COUNT, id, id, 0) == 0);
|
__assert(createiocompqueue(controller, &pair->completion, QUEUEPAIR_ENTRY_COUNT, id, id, 0) == 0);
|
||||||
__assert(createiosubqueue(controller, &pair->submission, QUEUEPAIR_ENTRY_COUNT, id, id, 0) == 0);
|
__assert(createiosubqueue(controller, &pair->submission, QUEUEPAIR_ENTRY_COUNT, id, id, 0) == 0);
|
||||||
pair->controller = controller;
|
pair->controller = controller;
|
||||||
@@ -813,6 +814,8 @@ static void initcontroller(pcienum_t *e) {
|
|||||||
controller->adminqueue.completion.doorbell = GET_DOORBELL(controller->bar0, 0, 1, controller->dbstride);
|
controller->adminqueue.completion.doorbell = GET_DOORBELL(controller->bar0, 0, 1, controller->dbstride);
|
||||||
controller->adminqueue.completion.phase = 1;
|
controller->adminqueue.completion.phase = 1;
|
||||||
|
|
||||||
|
dpc_prepare(&controller->adminqueue.dpc, nvme_dpc);
|
||||||
|
|
||||||
SPINLOCK_INIT(controller->adminqueue.lock);
|
SPINLOCK_INIT(controller->adminqueue.lock);
|
||||||
SEMAPHORE_INIT(&controller->adminqueue.entrysem, QUEUEPAIR_ENTRY_COUNT);
|
SEMAPHORE_INIT(&controller->adminqueue.entrysem, QUEUEPAIR_ENTRY_COUNT);
|
||||||
|
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ static void vioblk_dpc(context_t *context, dpcarg_t arg) {
|
|||||||
|
|
||||||
static void vioblk_irq(isr_t *isr, context_t *context) {
|
static void vioblk_irq(isr_t *isr, context_t *context) {
|
||||||
vioblkdev_t *blkdev = isr->priv;
|
vioblkdev_t *blkdev = isr->priv;
|
||||||
dpc_enqueue(&blkdev->queuedpc, vioblk_dpc, blkdev);
|
dpc_enqueue(&blkdev->queuedpc, blkdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
// driver and device are physical addresses
|
// driver and device are physical addresses
|
||||||
@@ -176,6 +176,7 @@ int vioblk_newdevice(viodevice_t *viodevice) {
|
|||||||
// initialize device object
|
// initialize device object
|
||||||
vioblkdev_t *blkdev = alloc(sizeof(vioblkdev_t));
|
vioblkdev_t *blkdev = alloc(sizeof(vioblkdev_t));
|
||||||
__assert(blkdev);
|
__assert(blkdev);
|
||||||
|
dpc_prepare(&blkdev->queuedpc, vioblk_dpc);
|
||||||
|
|
||||||
static int id = 0;
|
static int id = 0;
|
||||||
volatile blkdevconfig_t *blkconfig = viodevice->devconfig;
|
volatile blkdevconfig_t *blkconfig = viodevice->devconfig;
|
||||||
|
|||||||
@@ -43,7 +43,8 @@ static int loopback_sendpacket(netdev_t *netdev, netdesc_t desc, mac_t targetmac
|
|||||||
memcpy(desc.address, ðframe, sizeof(ethframe_t));
|
memcpy(desc.address, ðframe, sizeof(ethframe_t));
|
||||||
|
|
||||||
dpc_t dpc = {0};
|
dpc_t dpc = {0};
|
||||||
dpc_enqueue(&dpc, rx_dpc, desc.address);
|
dpc_prepare(&dpc, rx_dpc);
|
||||||
|
dpc_enqueue(&dpc, desc.address);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -152,10 +152,10 @@ static void rtl8169_isr(isr_t *self, context_t *) {
|
|||||||
outw(dev->bar.address + REGISTER_IRQ_STATUS, status);
|
outw(dev->bar.address + REGISTER_IRQ_STATUS, status);
|
||||||
|
|
||||||
if (status & (REGISTER_IRQ_STATUS_TX_OK | REGISTER_IRQ_STATUS_TX_ERROR))
|
if (status & (REGISTER_IRQ_STATUS_TX_OK | REGISTER_IRQ_STATUS_TX_ERROR))
|
||||||
dpc_enqueue(&dev->tx_dpc, rtl8169_dpc_tx, dev);
|
dpc_enqueue(&dev->tx_dpc, dev);
|
||||||
|
|
||||||
if (status & (REGISTER_IRQ_STATUS_RX_OK | REGISTER_IRQ_STATUS_RX_ERROR))
|
if (status & (REGISTER_IRQ_STATUS_RX_OK | REGISTER_IRQ_STATUS_RX_ERROR))
|
||||||
dpc_enqueue(&dev->rx_dpc, rtl8169_dpc_rx, dev);
|
dpc_enqueue(&dev->rx_dpc, dev);
|
||||||
|
|
||||||
status = inw(dev->bar.address + REGISTER_IRQ_STATUS);
|
status = inw(dev->bar.address + REGISTER_IRQ_STATUS);
|
||||||
}
|
}
|
||||||
@@ -311,7 +311,7 @@ static void init_controller(pcienum_t *pci_enum) {
|
|||||||
|
|
||||||
outb(pci_bar.address + REGISTER_COMMAND, REGISTER_COMMAND_TX_ENABLE);
|
outb(pci_bar.address + REGISTER_COMMAND, REGISTER_COMMAND_TX_ENABLE);
|
||||||
outd(pci_bar.address + REGISTER_TX_CONFIG, REGISTER_TX_CONFIG_DMA_BURST_UNLIMITED | REGISTER_TX_CONFIG_IFG_NORMAL);
|
outd(pci_bar.address + REGISTER_TX_CONFIG, REGISTER_TX_CONFIG_DMA_BURST_UNLIMITED | REGISTER_TX_CONFIG_IFG_NORMAL);
|
||||||
|
|
||||||
outw(pci_bar.address + REGISTER_RX_MAX_SIZE, 1518);
|
outw(pci_bar.address + REGISTER_RX_MAX_SIZE, 1518);
|
||||||
// 128 * 0xc, enough for an ethernet MTU (while 0xb would be enough, the datasheet says that it must be larger than the max size)
|
// 128 * 0xc, enough for an ethernet MTU (while 0xb would be enough, the datasheet says that it must be larger than the max size)
|
||||||
outb(pci_bar.address + REGISTER_TX_MAX_SIZE, 0xc);
|
outb(pci_bar.address + REGISTER_TX_MAX_SIZE, 0xc);
|
||||||
@@ -337,6 +337,9 @@ static void init_controller(pcienum_t *pci_enum) {
|
|||||||
SEMAPHORE_INIT(&netdev->tx_semaphore, TX_DESCRIPTOR_COUNT);
|
SEMAPHORE_INIT(&netdev->tx_semaphore, TX_DESCRIPTOR_COUNT);
|
||||||
SPINLOCK_INIT(netdev->tx_lock);
|
SPINLOCK_INIT(netdev->tx_lock);
|
||||||
|
|
||||||
|
dpc_prepare(&netdev->tx_dpc, rtl8169_dpc_tx);
|
||||||
|
dpc_prepare(&netdev->rx_dpc, rtl8169_dpc_rx);
|
||||||
|
|
||||||
isr->priv = netdev;
|
isr->priv = netdev;
|
||||||
|
|
||||||
char name[10];
|
char name[10];
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ static void rx_dpc(context_t *context, dpcarg_t arg) {
|
|||||||
|
|
||||||
static void rx_irq(isr_t *isr, context_t *context) {
|
static void rx_irq(isr_t *isr, context_t *context) {
|
||||||
vionetdev_t *netdev = isr->priv;
|
vionetdev_t *netdev = isr->priv;
|
||||||
dpc_enqueue(&netdev->rxdpc, rx_dpc, netdev);
|
dpc_enqueue(&netdev->rxdpc, netdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void tx_dpc(context_t *context, dpcarg_t arg) {
|
static void tx_dpc(context_t *context, dpcarg_t arg) {
|
||||||
@@ -75,7 +75,7 @@ static void tx_dpc(context_t *context, dpcarg_t arg) {
|
|||||||
|
|
||||||
static void tx_irq(isr_t *isr, context_t *context) {
|
static void tx_irq(isr_t *isr, context_t *context) {
|
||||||
vionetdev_t *netdev = isr->priv;
|
vionetdev_t *netdev = isr->priv;
|
||||||
dpc_enqueue(&netdev->txdpc, tx_dpc, netdev);
|
dpc_enqueue(&netdev->txdpc, netdev);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define PREFIX_SIZE (sizeof(ethframe_t) + sizeof(vioframe_t))
|
#define PREFIX_SIZE (sizeof(ethframe_t) + sizeof(vioframe_t))
|
||||||
@@ -178,6 +178,8 @@ int vionet_newdevice(viodevice_t *viodevice) {
|
|||||||
netdev->netdev.allocdesc = vionet_allocdesc;
|
netdev->netdev.allocdesc = vionet_allocdesc;
|
||||||
netdev->netdev.freedesc = vionet_freedesc;
|
netdev->netdev.freedesc = vionet_freedesc;
|
||||||
__assert(hashtable_init(&netdev->netdev.arpcache, 30) == 0);
|
__assert(hashtable_init(&netdev->netdev.arpcache, 30) == 0);
|
||||||
|
dpc_prepare(&netdev->rxdpc, rx_dpc);
|
||||||
|
dpc_prepare(&netdev->txdpc, tx_dpc);
|
||||||
|
|
||||||
// initialize queues
|
// initialize queues
|
||||||
size_t rxsize = min(QUEUE_MAX_SIZE, virtio_queuesize(viodevice, 0));
|
size_t rxsize = min(QUEUE_MAX_SIZE, virtio_queuesize(viodevice, 0));
|
||||||
|
|||||||
@@ -39,13 +39,19 @@ static void isrfn(isr_t *self, context_t *context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void dpc_enqueue(dpc_t *dpc, dpcfn_t fn, dpcarg_t arg) {
|
void dpc_prepare(dpc_t *dpc, dpcfn_t fn) {
|
||||||
|
dpc->fn = fn;
|
||||||
|
dpc->enqueued = false;
|
||||||
|
dpc->next = NULL;
|
||||||
|
dpc->prev = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void dpc_enqueue(dpc_t *dpc, dpcarg_t arg) {
|
||||||
bool entrystate = interrupt_set(false);
|
bool entrystate = interrupt_set(false);
|
||||||
|
|
||||||
if (dpc->enqueued)
|
if (dpc->enqueued)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
|
||||||
dpc->fn = fn;
|
|
||||||
dpc->arg = arg;
|
dpc->arg = arg;
|
||||||
dpc->enqueued = true;
|
dpc->enqueued = true;
|
||||||
insert(dpc);
|
insert(dpc);
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ static __attribute__((noreturn)) void switch_thread(thread_t *thread) {
|
|||||||
thread_t* current = current_thread();
|
thread_t* current = current_thread();
|
||||||
|
|
||||||
sched_thread_running_callback(thread);
|
sched_thread_running_callback(thread);
|
||||||
|
|
||||||
current_cpu()->thread = thread;
|
current_cpu()->thread = thread;
|
||||||
|
|
||||||
if(current == NULL || thread->vmmctx != current->vmmctx)
|
if(current == NULL || thread->vmmctx != current->vmmctx)
|
||||||
@@ -230,7 +230,7 @@ static void dopreempt() {
|
|||||||
switch_thread(next);
|
switch_thread(next);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void preempt_dpc(context_t *context, dpcarg_t arg) {
|
static void sched_reschedule_dpc(context_t *context, dpcarg_t arg) {
|
||||||
thread_t* current = current_thread();
|
thread_t* current = current_thread();
|
||||||
interrupt_set(false);
|
interrupt_set(false);
|
||||||
|
|
||||||
@@ -250,18 +250,18 @@ static void preempt_dpc(context_t *context, dpcarg_t arg) {
|
|||||||
|
|
||||||
// IPL_DPC
|
// IPL_DPC
|
||||||
static void reschedule_timer_dpc(context_t *context, dpcarg_t arg) {
|
static void reschedule_timer_dpc(context_t *context, dpcarg_t arg) {
|
||||||
dpc_enqueue(¤t_cpu()->reschedule_dpc, preempt_dpc, NULL);
|
dpc_enqueue(¤t_cpu()->reschedule_dpc, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
// IPL_MAX
|
// IPL_MAX
|
||||||
static void reschedule_ipi(isr_t *, context_t *) {
|
static void reschedule_ipi(isr_t *, context_t *) {
|
||||||
dpc_enqueue(¤t_cpu()->reschedule_dpc, preempt_dpc, NULL);
|
dpc_enqueue(¤t_cpu()->reschedule_dpc, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sched_preempt_cpu(cpu_t *cpu) {
|
void sched_preempt_cpu(cpu_t *cpu) {
|
||||||
long ipl = interrupt_raiseipl(IPL_DPC);
|
long ipl = interrupt_raiseipl(IPL_DPC);
|
||||||
if (cpu == current_cpu()) {
|
if (cpu == current_cpu()) {
|
||||||
dpc_enqueue(&cpu->reschedule_dpc, preempt_dpc, NULL);
|
dpc_enqueue(&cpu->reschedule_dpc, NULL);
|
||||||
} else {
|
} else {
|
||||||
arch_smp_send_ipi(cpu, cpu->reschedule_isr, ARCH_SMP_IPI_TARGET, false);
|
arch_smp_send_ipi(cpu, cpu->reschedule_isr, ARCH_SMP_IPI_TARGET, false);
|
||||||
}
|
}
|
||||||
@@ -347,6 +347,7 @@ void sched_load_balancer(context_t *, dpcarg_t);
|
|||||||
void sched_ap_entry() {
|
void sched_ap_entry() {
|
||||||
SPINLOCK_INIT(current_cpu()->sched_lock);
|
SPINLOCK_INIT(current_cpu()->sched_lock);
|
||||||
|
|
||||||
|
dpc_prepare(¤t_cpu()->reschedule_dpc, sched_reschedule_dpc);
|
||||||
set_up_bitmaps();
|
set_up_bitmaps();
|
||||||
|
|
||||||
current_cpu()->schedulerstack = vmm_map(NULL, SCHEDULER_STACK_SIZE, VMM_FLAGS_ALLOCATE, ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_WRITE | ARCH_MMU_FLAGS_NOEXEC, NULL);
|
current_cpu()->schedulerstack = vmm_map(NULL, SCHEDULER_STACK_SIZE, VMM_FLAGS_ALLOCATE, ARCH_MMU_FLAGS_READ | ARCH_MMU_FLAGS_WRITE | ARCH_MMU_FLAGS_NOEXEC, NULL);
|
||||||
@@ -374,7 +375,8 @@ void sched_init() {
|
|||||||
|
|
||||||
SPINLOCK_INIT(current_cpu()->sched_lock);
|
SPINLOCK_INIT(current_cpu()->sched_lock);
|
||||||
SPINLOCK_INIT(sched_idle_cpu_bitmap_lock);
|
SPINLOCK_INIT(sched_idle_cpu_bitmap_lock);
|
||||||
|
|
||||||
|
dpc_prepare(¤t_cpu()->reschedule_dpc, sched_reschedule_dpc);
|
||||||
set_up_bitmaps();
|
set_up_bitmaps();
|
||||||
|
|
||||||
__assert(bitmap_init(&sched_idle_cpu_bitmap, arch_smp_get_cpu_count()) == 0);
|
__assert(bitmap_init(&sched_idle_cpu_bitmap, arch_smp_get_cpu_count()) == 0);
|
||||||
|
|||||||
@@ -60,7 +60,7 @@ static void timercheck(timer_t *timer) {
|
|||||||
else
|
else
|
||||||
entry->fired = true;
|
entry->fired = true;
|
||||||
|
|
||||||
dpc_enqueue(&entry->dpc, entry->fn, entry->arg);
|
dpc_enqueue(&entry->dpc, entry->arg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -87,7 +87,7 @@ void timer_isr(timer_t *timer, context_t *context) {
|
|||||||
else
|
else
|
||||||
oldentry->fired = true;
|
oldentry->fired = true;
|
||||||
|
|
||||||
dpc_enqueue(&oldentry->dpc, oldentry->fn, oldentry->arg);
|
dpc_enqueue(&oldentry->dpc, oldentry->arg);
|
||||||
|
|
||||||
leave:
|
leave:
|
||||||
timercheck(timer);
|
timercheck(timer);
|
||||||
@@ -143,9 +143,9 @@ void timer_insert(timer_t *timer, timerentry_t *entry, dpcfn_t fn, dpcarg_t arg,
|
|||||||
|
|
||||||
memset(entry, 0, sizeof(timerentry_t));
|
memset(entry, 0, sizeof(timerentry_t));
|
||||||
entry->repeatus = repeating ? us : 0;
|
entry->repeatus = repeating ? us : 0;
|
||||||
entry->fn = fn;
|
|
||||||
entry->arg = arg;
|
|
||||||
entry->fired = false;
|
entry->fired = false;
|
||||||
|
entry->arg = arg;
|
||||||
|
dpc_prepare(&entry->dpc, fn);
|
||||||
insert(timer, entry, us);
|
insert(timer, entry, us);
|
||||||
|
|
||||||
if (timer->running) {
|
if (timer->running) {
|
||||||
|
|||||||
Reference in New Issue
Block a user