BBS水木清华站∶精华区
发信人: foxsen (曙光初现), 信区: Linux
标 题: Re: linux运行多任务难到这么难么
发信站: BBS 水木清华站 (Fri Oct 6 18:59:49 2000)
这里有一个简化版的for 2.4.0-test8
--- linux-2.4.0-test8/include/linux/sched.h Sat Sep 9 16:19:30 2000
+++ linux-akpm/include/linux/sched.h Tue Sep 12 19:45:11 2000
@@ -150,6 +150,9 @@
extern signed long FASTCALL(schedule_timeout(signed long timeout));
asmlinkage void schedule(void);
+#define conditional_schedule_needed() (current->need_resched)
+#define conditional_schedule() do { if
(conditional_schedule_needed()) schedule(); } while (0)
+
/*
* The default fd array needs to be at least BITS_PER_LONG,
* as this is the granularity returned by copy_fdset().
--- linux-2.4.0-test8/include/linux/mm.h Sat Sep 9 16:19:30 2000
+++ linux-akpm/include/linux/mm.h Tue Sep 12 19:45:11 2000
@@ -179,6 +179,10 @@
/* bits 21-30 unused */
#define PG_reserved 31
+/* Actions for zap_page_range() */
+#define ZPR_FLUSH_CACHE 1 /* Do flush_cache_range() prior to releasing
pages */
+#define ZPR_FLUSH_TLB 2 /* Do flush_tlb_range() after releasing
pages */
+#define ZPR_COND_RESCHED 4 /* Do a conditional_schedule()
occasionally */
/* Make it prettier to test the above... */
#define Page_Uptodate(page) test_bit(PG_uptodate, &(page)->flags)
@@ -360,7 +364,7 @@
extern int map_zero_setup(struct vm_area_struct *);
-extern void zap_page_range(struct mm_struct *mm, unsigned long address,
unsigned long size);
+extern void zap_page_range(struct mm_struct *mm, unsigned long address,
unsigned long size, int actions);
extern int copy_page_range(struct mm_struct *dst, struct mm_struct
*src, struct vm_area_struct *vma);
extern int remap_page_range(unsigned long from, unsigned long to,
unsigned long size, pgprot_t prot);
extern int zeromap_page_range(unsigned long from, unsigned long size,
pgprot_t prot);
--- linux-2.4.0-test8/mm/filemap.c Sat Sep 9 16:19:30 2000
+++ linux-akpm/mm/filemap.c Tue Sep 12 19:36:55 2000
@@ -191,6 +191,7 @@
start = (lstart + PAGE_CACHE_SIZE - 1) >> PAGE_CACHE_SHIFT;
repeat:
+ conditional_schedule(); /* sys_unlink() */
head = &mapping->pages;
spin_lock(&pagecache_lock);
curr = head->next;
@@ -252,6 +253,8 @@
/* we need pagemap_lru_lock for list_del() ... subtle code below */
spin_lock(&pagemap_lru_lock);
while (count > 0 && (page_lru = lru_cache.prev) != &lru_cache) {
+ if (conditional_schedule_needed())
+ goto out_resched;
page = list_entry(page_lru, struct page, lru);
list_del(page_lru);
@@ -368,6 +371,10 @@
spin_unlock(&pagemap_lru_lock);
return ret;
+out_resched:
+ spin_unlock(&pagemap_lru_lock);
+ schedule();
+ return ret;
}
static inline struct page * __find_page_nolock(struct address_space
*mapping, unsigned long offset, struct page *page)
@@ -446,6 +453,7 @@
page_cache_get(page);
spin_unlock(&pagecache_lock);
+ conditional_schedule(); /* sys_msync() */
lock_page(page);
/* The buffers could have been free'd while we waited for the page
lock */
@@ -1081,6 +1089,7 @@
* "pos" here (the actor routine has to update the user buffer
* pointers and the remaining count).
*/
+ conditional_schedule(); /* sys_read() */
nr = actor(desc, page, offset, nr);
offset += nr;
index += offset >> PAGE_CACHE_SHIFT;
@@ -1533,6 +1542,7 @@
* vma/file is guaranteed to exist in the unmap/sync cases because
* mmap_sem is held.
*/
+ conditional_schedule(); /* sys_msync() */
return page->mapping->a_ops->writepage(file, page);
}
@@ -1670,6 +1680,7 @@
if (address >= end)
BUG();
do {
+ conditional_schedule(); /* unmapping large mapped files */
error |= filemap_sync_pmd_range(dir, address, end - address, vma,
flags);
address = (address + PGDIR_SIZE) & PGDIR_MASK;
dir++;
@@ -2020,9 +2031,8 @@
if (vma->vm_flags & VM_LOCKED)
return -EINVAL;
- flush_cache_range(vma->vm_mm, start, end);
- zap_page_range(vma->vm_mm, start, end - start);
- flush_tlb_range(vma->vm_mm, start, end);
+ zap_page_range(vma->vm_mm, start, end - start,
+ ZPR_FLUSH_CACHE|ZPR_FLUSH_TLB|ZPR_COND_RESCHED); /*
sys_madvise(MADV_DONTNEED) */
return 0;
}
@@ -2486,6 +2496,7 @@
unsigned long bytes, index, offset;
char *kaddr;
+ conditional_schedule(); /* sys_write() */
/*
* Try to find the page in the cache. If it isn't there,
* allocate a free page.
--- linux-2.4.0-test8/fs/buffer.c Sat Sep 9 16:19:29 2000
+++ linux-akpm/fs/buffer.c Tue Sep 12 19:36:55 2000
@@ -2220,6 +2220,7 @@
__wait_on_buffer(p);
} else if (buffer_dirty(p))
ll_rw_block(WRITE, 1, &p);
+ conditional_schedule(); /* sys_msync() */
} while (tmp != bh);
}
--- linux-2.4.0-test8/fs/dcache.c Thu Aug 24 21:07:22 2000
+++ linux-akpm/fs/dcache.c Tue Sep 12 19:36:55 2000
@@ -301,7 +301,7 @@
* removed.
* Called with dcache_lock, drops it and then regains.
*/
-static inline void prune_one_dentry(struct dentry * dentry)
+static inline void prune_one_dentry(struct dentry * dentry, int
*resched_count)
{
struct dentry * parent;
@@ -312,6 +312,10 @@
d_free(dentry);
if (parent != dentry)
dput(parent);
+ if ((*resched_count)++ == 10) {
+ resched_count = 0; /* Hack buys 0.6% in bonnie++ */
+ conditional_schedule(); /* pruning many dentries (sys_rmdir) */
+ }
spin_lock(&dcache_lock);
}
@@ -330,6 +334,8 @@
void prune_dcache(int count)
{
+ int resched_count = 0;
+
spin_lock(&dcache_lock);
for (;;) {
struct dentry *dentry;
@@ -347,7 +353,7 @@
if (atomic_read(&dentry->d_count))
BUG();
- prune_one_dentry(dentry);
+ prune_one_dentry(dentry, &resched_count);
if (!--count)
break;
}
@@ -380,6 +386,7 @@
{
struct list_head *tmp, *next;
struct dentry *dentry;
+ int resched_count = 0;
/*
* Pass one ... move the dentries for the specified
@@ -413,7 +420,7 @@
dentry_stat.nr_unused--;
list_del(tmp);
INIT_LIST_HEAD(tmp);
- prune_one_dentry(dentry);
+ prune_one_dentry(dentry, &resched_count);
goto repeat;
}
spin_unlock(&dcache_lock);
@@ -482,7 +489,7 @@
{
struct dentry *this_parent = parent;
struct list_head *next;
- int found = 0;
+ int found = 0, count = 0;
spin_lock(&dcache_lock);
repeat:
@@ -497,6 +504,13 @@
list_add(&dentry->d_lru, dentry_unused.prev);
found++;
}
+
+ if (count++ == 500 && found > 10) {
+ count = 0;
+ if (conditional_schedule_needed()) /* Typically sys_rmdir() */
+ goto out;
+ }
+
/*
* Descend a level if the d_subdirs list is non-empty.
*/
@@ -521,6 +535,7 @@
#endif
goto resume;
}
+out:
spin_unlock(&dcache_lock);
return found;
}
@@ -536,8 +551,10 @@
{
int found;
- while ((found = select_parent(parent)) != 0)
+ while ((found = select_parent(parent)) != 0) {
prune_dcache(found);
+ conditional_schedule(); /* Typically sys_rmdir() */
+ }
}
/*
--- linux-2.4.0-test8/fs/inode.c Thu Aug 24 21:07:23 2000
+++ linux-akpm/fs/inode.c Tue Sep 12 19:36:55 2000
@@ -200,7 +200,7 @@
spin_unlock(&inode_lock);
write_inode(inode, sync);
-
+ conditional_schedule(); /* kupdate: sync_old_inodes() */
spin_lock(&inode_lock);
inode->i_state &= ~I_LOCK;
wake_up(&inode->i_wait);
--- linux-2.4.0-test8/mm/memory.c Sat Sep 9 16:19:30 2000
+++ linux-akpm/mm/memory.c Tue Sep 12 19:36:55 2000
@@ -243,6 +243,7 @@
goto out;
src_pte++;
dst_pte++;
+ conditional_schedule(); /* sys_fork(), with a large shm seg */
} while ((unsigned long)src_pte & PTE_TABLE_MASK);
cont_copy_pmd_range: src_pmd++;
@@ -347,7 +348,7 @@
/*
* remove user pages in a given range.
*/
-void zap_page_range(struct mm_struct *mm, unsigned long address,
unsigned long size)
+static void do_zap_page_range(struct mm_struct *mm, unsigned long
address, unsigned long size)
{
pgd_t * dir;
unsigned long end = address + size;
@@ -381,6 +382,25 @@
mm->rss = 0;
}
+#define MAX_ZAP_BYTES 256*PAGE_SIZE
+
+void zap_page_range(struct mm_struct *mm, unsigned long address,
unsigned long size, int actions)
+{
+ while (size) {
+ unsigned long chunk = size;
+ if (actions & ZPR_COND_RESCHED && chunk > MAX_ZAP_BYTES)
+ chunk = MAX_ZAP_BYTES;
+ if (actions & ZPR_FLUSH_CACHE)
+ flush_cache_range(mm, address, address + chunk);
+ do_zap_page_range(mm, address, chunk);
+ if (actions & ZPR_FLUSH_TLB)
+ flush_tlb_range(mm, address, address + chunk);
+ if (actions & ZPR_COND_RESCHED)
+ conditional_schedule();
+ address += chunk;
+ size -= chunk;
+ }
+}
/*
* Do a quick page-table lookup for a single page.
@@ -936,9 +956,7 @@
/* mapping wholly truncated? */
if (mpnt->vm_pgoff >= pgoff) {
- flush_cache_range(mm, start, end);
- zap_page_range(mm, start, len);
- flush_tlb_range(mm, start, end);
+ zap_page_range(mm, start, len, ZPR_FLUSH_CACHE|ZPR_FLUSH_TLB);
continue;
}
@@ -955,9 +973,7 @@
partial_clear(mpnt, start);
start = (start + ~PAGE_MASK) & PAGE_MASK;
}
- flush_cache_range(mm, start, end);
- zap_page_range(mm, start, len);
- flush_tlb_range(mm, start, end);
+ zap_page_range(mm, start, len, ZPR_FLUSH_CACHE|ZPR_FLUSH_TLB);
} while ((mpnt = mpnt->vm_next_share) != NULL);
}
@@ -1239,7 +1255,9 @@
pgd = pgd_offset(mm, address);
pmd = pmd_alloc(pgd, address);
-
+
+ conditional_schedule(); /* Pinning down many physical pages (kiobufs,
mlockall) */
+
if (pmd) {
pte_t * pte = pte_alloc(pmd, address);
if (pte)
--- linux-2.4.0-test8/mm/mmap.c Sat Sep 9 16:19:30 2000
+++ linux-akpm/mm/mmap.c Tue Sep 12 19:36:55 2000
@@ -337,9 +337,8 @@
vma->vm_file = NULL;
fput(file);
/* Undo any partial mapping done by a device driver. */
- flush_cache_range(mm, vma->vm_start, vma->vm_end);
- zap_page_range(mm, vma->vm_start, vma->vm_end - vma->vm_start);
- flush_tlb_range(mm, vma->vm_start, vma->vm_end);
+ zap_page_range(mm, vma->vm_start, vma->vm_end - vma->vm_start,
+ ZPR_FLUSH_CACHE|ZPR_FLUSH_TLB);
free_vma:
kmem_cache_free(vm_area_cachep, vma);
return error;
@@ -708,10 +707,8 @@
}
remove_shared_vm_struct(mpnt);
mm->map_count--;
-
- flush_cache_range(mm, st, end);
- zap_page_range(mm, st, size);
- flush_tlb_range(mm, st, end);
+ zap_page_range(mm, st, size,
+ ZPR_FLUSH_CACHE|ZPR_FLUSH_TLB|ZPR_COND_RESCHED); /* sys_munmap()
*/
/*
* Fix the mapping, and free the old area if it wasn't reused.
@@ -861,8 +858,7 @@
}
mm->map_count--;
remove_shared_vm_struct(mpnt);
- flush_cache_range(mm, start, end);
- zap_page_range(mm, start, size);
+ zap_page_range(mm, start, size, ZPR_COND_RESCHED|ZPR_FLUSH_CACHE);
/* sys_exit() */
if (mpnt->vm_file)
fput(mpnt->vm_file);
kmem_cache_free(vm_area_cachep, mpnt);
--- linux-2.4.0-test8/mm/mremap.c Sat Jun 24 15:39:47 2000
+++ linux-akpm/mm/mremap.c Tue Sep 12 19:36:55 2000
@@ -118,8 +118,7 @@
flush_cache_range(mm, new_addr, new_addr + len);
while ((offset += PAGE_SIZE) < len)
move_one_page(mm, new_addr + offset, old_addr + offset);
- zap_page_range(mm, new_addr, len);
- flush_tlb_range(mm, new_addr, new_addr + len);
+ zap_page_range(mm, new_addr, len, ZPR_FLUSH_TLB);
return -1;
}
--- linux-2.4.0-test8/mm/vmscan.c Sat Sep 9 16:19:30 2000
+++ linux-akpm/mm/vmscan.c Tue Sep 12 19:36:55 2000
@@ -293,6 +293,8 @@
return result;
if (!mm->swap_cnt)
return 0;
+ if (conditional_schedule_needed())
+ return 0;
address = (address + PGDIR_SIZE) & PGDIR_MASK;
pgdir++;
} while (address && (address < end));
@@ -313,6 +315,7 @@
* Find the proper vm-area after freezing the vma chain
* and ptes.
*/
+continue_scan:
vmlist_access_lock(mm);
vma = find_vma(mm, address);
if (vma) {
@@ -323,6 +326,14 @@
int result = swap_out_vma(mm, vma, address, gfp_mask);
if (result)
return result;
+ if (!mm->swap_cnt)
+ break;
+ if (conditional_schedule_needed()) {
+ vmlist_access_unlock(mm);
+ schedule();
+ address = mm->swap_address;
+ goto continue_scan;
+ }
vma = vma->vm_next;
if (!vma)
break;
@@ -529,6 +540,7 @@
goto done;
while (shm_swap(priority, gfp_mask)) {
+ conditional_schedule(); /* required if there's much sysv shm */
if (!--count)
goto done;
}
--- linux-2.4.0-test8/ipc/shm.c Sat Sep 9 16:19:30 2000
+++ linux-akpm/ipc/shm.c Tue Sep 12 19:36:55 2000
@@ -619,6 +619,7 @@
for (i = 0, rss = 0, swp = 0; i < pages ; i++) {
pte_t pte;
pte = dir[i/PTES_PER_PAGE][i%PTES_PER_PAGE];
+ conditional_schedule(); /* releasing large shm segs */
if (pte_none(pte))
continue;
if (pte_present(pte)) {
--- linux-2.4.0-test8/drivers/char/mem.c Sat Jun 24 15:39:43 2000
+++ linux-akpm/drivers/char/mem.c Tue Sep 12 19:36:55 2000
@@ -373,8 +373,7 @@
if (count > size)
count = size;
- flush_cache_range(mm, addr, addr + count);
- zap_page_range(mm, addr, count);
+ zap_page_range(mm, addr, count, ZPR_FLUSH_CACHE);
zeromap_page_range(addr, count, PAGE_COPY);
flush_tlb_range(mm, addr, addr + count);
--- linux-2.4.0-test8/fs/ext2/namei.c Sat Sep 9 16:19:30 2000
+++ linux-akpm/fs/ext2/namei.c Tue Sep 12 19:36:58 2000
@@ -90,6 +90,8 @@
struct ext2_dir_entry_2 * de;
char * dlimit;
+ conditional_schedule(); /* Searching large directories */
+
if ((block % NAMEI_RA_BLOCKS) == 0 && toread) {
ll_rw_block (READ, toread, bh_read);
toread = 0;
@@ -229,6 +231,7 @@
offset = 0;
de = (struct ext2_dir_entry_2 *) bh->b_data;
while (1) {
+ conditional_schedule(); /* Adding to a large directory */
if ((char *)de >= sb->s_blocksize + bh->b_data) {
brelse (bh);
bh = NULL;
【 在 althea (痛并快乐着) 的大作中提到: 】
∶ 哪里可以找到?
--
※ 来源:·BBS 水木清华站 smth.org·[FROM: 159.226.40.132]
BBS水木清华站∶精华区