|
|
| version 1.2, 2004/01/20 05:04:06 | version 1.3, 2004/03/29 14:06:31 |
|---|---|
| Line 30 | Line 30 |
| #include <sys/systm.h> | #include <sys/systm.h> |
| #include <sys/kernel.h> | #include <sys/kernel.h> |
| #include <sys/slaballoc.h> | #include <sys/slaballoc.h> |
| #include <sys/mpipe.h> | |
| #include <sys/mbuf.h> | #include <sys/mbuf.h> |
| #include <sys/vmmeter.h> | #include <sys/vmmeter.h> |
| #include <sys/lock.h> | #include <sys/lock.h> |
| #include <sys/thread.h> | #include <sys/thread.h> |
| #include <sys/globaldata.h> | #include <sys/globaldata.h> |
| #include <sys/mpipe.h> | |
| #include <sys/thread2.h> | #include <sys/thread2.h> |
| #define arysize(ary) (sizeof(ary)/sizeof((ary)[0])) | void mpipe_rebalance(malloc_pipe_t mpipe); |
| typedef struct mpipe_buf { | typedef struct mpipe_buf { |
| TAILQ_ENTRY(mpipe_buf) entry; | TAILQ_ENTRY(mpipe_buf) entry; |
| Line 52 typedef struct mpipe_buf { | Line 52 typedef struct mpipe_buf { |
| */ | */ |
| void | void |
| mpipe_init(malloc_pipe_t mpipe, malloc_type_t type, int bytes, | mpipe_init(malloc_pipe_t mpipe, malloc_type_t type, int bytes, |
| int nnow, int nmax) | int global_nnom, int global_nmax, int cpu_nmax, |
| int mpflags) | |
| { | { |
| struct mpipe_buf *buf; | |
| int i; | |
| int mflags; | |
| if (bytes < sizeof(struct mpipe_buf)) | if (bytes < sizeof(struct mpipe_buf)) |
| bytes = sizeof(struct mpipe_buf); | bytes = sizeof(struct mpipe_buf); |
| if (global_nnom < cpu_nmax * ncpus) | |
| global_nnom = cpu_nmax * ncpus; | |
| if (global_nnom > global_nmax) | |
| global_nmax = global_nnom; | |
| bzero(mpipe, sizeof(struct malloc_pipe)); | bzero(mpipe, sizeof(struct malloc_pipe)); |
| TAILQ_INIT(&mpipe->queue); | |
| mpipe->type = type; | mpipe->type = type; |
| mpipe->bytes = bytes; | mpipe->bytes = bytes; |
| mpipe->max_count = nmax; | mpipe->max_count = global_nmax; |
| if (nnow > 0) { | mpipe->cpu_max = cpu_nmax; |
| void *buf; | mpipe->mpflags = mpflags; |
| buf = malloc(bytes, mpipe->type, M_WAITOK); | mflags = M_WAITOK; |
| KKASSERT(buf != NULL); | if ((mpflags & MPF_NO_ZERO) == 0) |
| ++mpipe->total_count; | mflags |= M_ZERO; |
| mpipe_free(mpipe, buf); | |
| while (--nnow > 0) { | for (i = 0; i <= SMP_MAXCPU; i++) |
| buf = malloc(bytes, mpipe->type, M_SYSNOWAIT); | TAILQ_INIT(&mpipe->queue[i]); |
| if (buf == NULL) | |
| break; | for (i = 1; i <= ncpus; i++) { |
| while (mpipe->queue_len[i] < mpipe->cpu_max) { | |
| buf = malloc(mpipe->bytes, mpipe->type, mflags); | |
| TAILQ_INSERT_TAIL(&mpipe->queue[i], buf, entry); | |
| ++mpipe->total_count; | ++mpipe->total_count; |
| mpipe_free(mpipe, buf); | ++mpipe->queue_len[i]; |
| --global_nnom; | |
| } | } |
| } | } |
| if (mpipe->max_count < mpipe->total_count) | |
| mpipe->max_count = mpipe->total_count; | TAILQ_INIT(&mpipe->queue[0]); |
| while (--global_nnom >= 0) { | |
| buf = malloc(mpipe->bytes, mpipe->type, mflags); | |
| TAILQ_INSERT_TAIL(&mpipe->queue[0], buf, entry); | |
| ++mpipe->total_count; | |
| ++mpipe->queue_len[0]; | |
| } | |
| } | } |
| void | void |
| mpipe_done(malloc_pipe_t mpipe) | mpipe_done(malloc_pipe_t mpipe) |
| { | { |
| struct mpipe_buf *buf; | mpipe_buf_t buf; |
| lwkt_tokref ilock; | |
| int i; | |
| KKASSERT(mpipe->free_count == mpipe->total_count); | lwkt_gettoken(&ilock, &mpipe->mpipe_token); |
| while (mpipe->free_count) { | KKASSERT(mpipe->queue_len[0] == mpipe->total_count); |
| buf = TAILQ_FIRST(&mpipe->queue); | for (i = 0; i < SMP_MAXCPU; i++) { |
| KKASSERT(buf != NULL); | while(! TAILQ_EMPTY(&mpipe->queue[i])) { |
| TAILQ_REMOVE(&mpipe->queue, buf, entry); | buf = TAILQ_FIRST(&mpipe->queue[i]); |
| --mpipe->free_count; | KKASSERT(buf != NULL); |
| --mpipe->total_count; | TAILQ_REMOVE(&mpipe->queue[i], buf, entry); |
| free(buf, mpipe->type); | --mpipe->queue_len[i]; |
| --mpipe->total_count; | |
| free(buf, mpipe->type); | |
| } | |
| KKASSERT(mpipe->queue_len[i] == 0); | |
| } | } |
| KKASSERT(TAILQ_EMPTY(&mpipe->queue)); | KKASSERT(mpipe->total_count == 0); |
| } | } |
| /* | /* |
| * Allocate an entry. flags can be M_RNOWAIT which tells us not to block. | * Allocation from MPIPE that can wait. Only drain the global queue. |
| * Unlike a normal malloc, if we block in mpipe_alloc() no deadlock will occur | |
| * because it will unblock the moment an existing in-use buffer is freed. | |
| */ | */ |
| void * | void * |
| mpipe_alloc(malloc_pipe_t mpipe, int flags) | mpipe_alloc_waitok(malloc_pipe_t mpipe) |
| { | { |
| mpipe_buf_t buf; | mpipe_buf_t buf = NULL; |
| lwkt_tokref ilock; | |
| int mflags = M_WAITOK; | |
| lwkt_gettoken(&ilock, &mpipe->mpipe_token); | |
| for (;;) { | |
| crit_enter(); | |
| if (mpipe->queue_len[0] > 0) { | |
| buf = TAILQ_FIRST(&mpipe->queue[0]); | |
| KKASSERT(buf != NULL); | |
| TAILQ_REMOVE(&mpipe->queue[0], buf, entry); | |
| --mpipe->queue_len[0]; | |
| if ((mpipe->mpflags & MPF_NO_ZERO) == 0) | |
| bzero(buf, mpipe->bytes); | |
| crit_exit(); | |
| lwkt_reltoken(&ilock); | |
| mpipe_rebalance(mpipe); | |
| return(buf); | |
| } | |
| crit_enter(); | |
| while (mpipe->free_count == 0) { | |
| if (mpipe->total_count < mpipe->max_count) { | if (mpipe->total_count < mpipe->max_count) { |
| ++mpipe->total_count; | if ((mpipe->mpflags & MPF_NO_ZERO) == 0) |
| if ((buf = malloc(mpipe->bytes, mpipe->type, flags)) != NULL) { | mflags |= M_ZERO; |
| crit_exit(); | |
| return(buf); | mpipe->total_count++; |
| } | |
| --mpipe->total_count; | |
| } else if (flags & M_RNOWAIT) { | |
| crit_exit(); | crit_exit(); |
| return(NULL); | lwkt_reltoken(&ilock); |
| } else { | buf = malloc(mpipe->bytes, mpipe->type, mflags); |
| mpipe->pending = 1; | KKASSERT(buf != NULL); |
| tsleep(mpipe, 0, "mpipe", 0); | |
| } | } |
| mpipe->pending = 1; | |
| tsleep(mpipe, 0, "mpipe", 0); | |
| } | |
| } | |
| /* | |
| * Allocation from MPIPE that can't wait. Try to drain the | |
| * local cpu queue first, if that is empty, drain the global | |
| * CPU | |
| */ | |
| void * | |
| mpipe_alloc_nowait(malloc_pipe_t mpipe) | |
| { | |
| globaldata_t gd = mycpu; | |
| mpipe_buf_t buf = NULL; | |
| lwkt_tokref ilock; | |
| int my_queue = gd->gd_cpuid + 1; | |
| int mflags = M_NOWAIT; | |
| /* First check the local CPU queue to avoid token acquisation. */ | |
| crit_enter(); | |
| if (mpipe->queue_len[my_queue] > 0) { | |
| buf = TAILQ_FIRST(&mpipe->queue[my_queue]); | |
| KKASSERT(buf != NULL); | |
| TAILQ_REMOVE(&mpipe->queue[my_queue], buf, entry); | |
| --mpipe->queue_len[my_queue]; | |
| if ((mpipe->mpflags & MPF_NO_ZERO) == 0) | |
| bzero(buf, mpipe->bytes); | |
| mpipe_rebalance(mpipe); | |
| crit_exit(); | |
| return(buf); | |
| } | |
| /* We have to acquire the token, unblock interrupts and get it. */ | |
| crit_exit(); | |
| lwkt_gettoken(&ilock, &mpipe->mpipe_token); | |
| crit_enter(); | |
| if (mpipe->queue_len[0] > 0) { | |
| buf = TAILQ_FIRST(&mpipe->queue[0]); | |
| KKASSERT(buf != NULL); | |
| TAILQ_REMOVE(&mpipe->queue[0], buf, entry); | |
| --mpipe->queue_len[0]; | |
| if ((mpipe->mpflags & MPF_NO_ZERO) == 0) | |
| bzero(buf, mpipe->bytes); | |
| crit_exit(); | |
| lwkt_reltoken(&ilock); | |
| return(buf); | |
| } | } |
| buf = TAILQ_FIRST(&mpipe->queue); | |
| KKASSERT(buf != NULL); | /* Recheck the local CPU queue again in case an interrupt freed something*/ |
| TAILQ_REMOVE(&mpipe->queue, buf, entry); | if (mpipe->queue_len[my_queue] > 0) { |
| --mpipe->free_count; | buf = TAILQ_FIRST(&mpipe->queue[my_queue]); |
| KKASSERT(buf != NULL); | |
| TAILQ_REMOVE(&mpipe->queue[my_queue], buf, entry); | |
| --mpipe->queue_len[my_queue]; | |
| if ((mpipe->mpflags & MPF_NO_ZERO) == 0) | |
| bzero(buf, mpipe->bytes); | |
| crit_exit(); | |
| lwkt_reltoken(&ilock); | |
| return(buf); | |
| } | |
| if (mpipe->total_count < mpipe->max_count) { | |
| if ((mpipe->mpflags & MPF_NO_ZERO) == 0) | |
| mflags |= M_ZERO; | |
| buf = malloc(mpipe->bytes, mpipe->type, mflags); | |
| if (buf) | |
| mpipe->total_count++; | |
| } | |
| crit_exit(); | crit_exit(); |
| if (flags & M_ZERO) | lwkt_reltoken(&ilock); |
| bzero(buf, mpipe->bytes); | |
| return(buf); | return(buf); |
| } | } |
| Line 140 mpipe_alloc(malloc_pipe_t mpipe, int fla | Line 244 mpipe_alloc(malloc_pipe_t mpipe, int fla |
| void | void |
| mpipe_free(malloc_pipe_t mpipe, void *vbuf) | mpipe_free(malloc_pipe_t mpipe, void *vbuf) |
| { | { |
| struct mpipe_buf *buf; | globaldata_t gd = mycpu; |
| mpipe_buf_t buf = NULL; | |
| lwkt_tokref ilock; | |
| int my_queue = gd->gd_cpuid + 1; | |
| if ((buf = vbuf) != NULL) { | if (vbuf == NULL) |
| crit_enter(); | return; |
| if (mpipe->total_count > mpipe->max_count) { | |
| --mpipe->total_count; | lwkt_gettoken(&ilock, &mpipe->mpipe_token); |
| crit_exit(); | crit_enter(); |
| free(buf, mpipe->type); | |
| } else { | /* first try to refill the current CPU queue */ |
| TAILQ_INSERT_TAIL(&mpipe->queue, buf, entry); | if (mpipe->queue_len[my_queue] < mpipe->cpu_max) { |
| ++mpipe->free_count; | TAILQ_INSERT_TAIL(&mpipe->queue[my_queue], buf, entry); |
| crit_exit(); | ++mpipe->queue_len[my_queue]; |
| if (mpipe->free_count >= (mpipe->total_count >> 2) + 1) { | crit_exit(); |
| if (mpipe->trigger) { | if (mpipe->pending) { |
| mpipe->trigger(mpipe->trigger_data); | mpipe->pending = 0; |
| } | wakeup(mpipe); |
| if (mpipe->pending) { | |
| mpipe->pending = 0; | |
| wakeup(mpipe); | |
| } | |
| } | |
| } | } |
| lwkt_reltoken(&ilock); | |
| mpipe_rebalance(mpipe); | |
| return; | |
| } | } |
| if (mpipe->total_count < mpipe->max_count) { | |
| TAILQ_INSERT_TAIL(&mpipe->queue[0], buf, entry); | |
| ++mpipe->queue_len[0]; | |
| crit_exit(); | |
| if (mpipe->pending) { | |
| mpipe->pending = 0; | |
| wakeup(mpipe); | |
| } | |
| lwkt_reltoken(&ilock); | |
| mpipe_rebalance(mpipe); | |
| return; | |
| } | |
| --mpipe->total_count; | |
| crit_exit(); | |
| lwkt_reltoken(&ilock); | |
| free(buf, mpipe->type); | |
| } | } |
| /* | |
| * Rebalance local CPU queue by trying to size it to max_cpu entries | |
| */ | |
| void | |
| mpipe_rebalance(malloc_pipe_t mpipe) | |
| { | |
| globaldata_t gd = mycpu; | |
| mpipe_buf_t buf; | |
| lwkt_tokref ilock; | |
| int my_queue = gd->gd_cpuid + 1; | |
| lwkt_gettoken(&ilock, &mpipe->mpipe_token); | |
| crit_enter(); | |
| while (mpipe->queue_len[my_queue] < mpipe->cpu_max && | |
| mpipe->queue_len[0] > 0) { | |
| buf = TAILQ_FIRST(&mpipe->queue[0]); | |
| TAILQ_REMOVE(&mpipe->queue[0], buf, entry); | |
| TAILQ_INSERT_TAIL(&mpipe->queue[my_queue], buf, entry); | |
| ++mpipe->queue_len[my_queue]; | |
| --mpipe->queue_len[0]; | |
| } | |
| while (mpipe->queue_len[my_queue] > mpipe->cpu_max) { | |
| buf = TAILQ_FIRST(&mpipe->queue[my_queue]); | |
| TAILQ_REMOVE(&mpipe->queue[my_queue], buf, entry); | |
| TAILQ_INSERT_TAIL(&mpipe->queue[0], buf, entry); | |
| ++mpipe->queue_len[0]; | |
| --mpipe->queue_len[my_queue]; | |
| } | |
| crit_exit(); | |
| lwkt_reltoken(&ilock); | |
| } |