Subversion Repositories HelenOS-historic

Rev

Rev 1411 | Rev 1415 | Go to most recent revision | Show entire file | Ignore whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 1411 Rev 1413
Line 448... Line 448...
448
    mutex_unlock(&AS->lock);
448
    mutex_unlock(&AS->lock);
449
    interrupts_restore(ipl);
449
    interrupts_restore(ipl);
450
    return 0;
450
    return 0;
451
}
451
}
452
 
452
 
453
/** Steal address space area from another task.
453
/** Share address space area with another or the same address space.
454
 *
454
 *
455
 * Address space area is stolen from another task
455
 * Address space area of anonymous memory is shared with a new address
456
 * Moreover, any existing mapping
456
 * space area. If the source address space area has not been shared so
457
 * is copied as well, providing thus a mechanism
457
 * far, a new sh_info is created and the original mapping is duplicated
458
 * for sharing group of pages. The source address
458
 * in its pagemap B+tree. The new address space are simply gets the
459
 * space area and any associated mapping is preserved.
459
 * sh_info of the source area.
460
 *
460
 *
461
 * @param src_task Pointer of source task
461
 * @param src_as Pointer to source address space
462
 * @param src_base Base address of the source address space area.
462
 * @param src_base Base address of the source address space area.
463
 * @param acc_size Expected size of the source area
463
 * @param acc_size Expected size of the source area
464
 * @param dst_base Target base address
464
 * @param dst_base Target base address
465
 *
465
 *
466
 * @return Zero on success or ENOENT if there is no such task or
466
 * @return Zero on success or ENOENT if there is no such task or
467
 *     if there is no such address space area,
467
 *     if there is no such address space area,
468
 *     EPERM if there was a problem in accepting the area or
468
 *     EPERM if there was a problem in accepting the area or
469
 *     ENOMEM if there was a problem in allocating destination
469
 *     ENOMEM if there was a problem in allocating destination
470
 *     address space area.
470
 *     address space area. ENOTSUP is returned if an attempt
-
 
471
 *     to share non-anonymous address space area is detected.
471
 */
472
 */
472
int as_area_steal(task_t *src_task, __address src_base, size_t acc_size,
473
int as_area_share(as_t *src_as, __address src_base, size_t acc_size,
473
          __address dst_base)
474
          __address dst_base)
474
{
475
{
475
    ipl_t ipl;
476
    ipl_t ipl;
476
    count_t i;
-
 
477
    as_t *src_as;      
-
 
478
    int src_flags;
477
    int src_flags;
479
    size_t src_size;
478
    size_t src_size;
480
    as_area_t *src_area, *dst_area;
479
    as_area_t *src_area, *dst_area;
-
 
480
    share_info_t *sh_info;
-
 
481
    link_t *cur;
481
 
482
 
482
    ipl = interrupts_disable();
483
    ipl = interrupts_disable();
483
    spinlock_lock(&src_task->lock);
-
 
484
    src_as = src_task->as;
-
 
485
   
-
 
486
    mutex_lock(&src_as->lock);
484
    mutex_lock(&src_as->lock);
487
    src_area = find_area_and_lock(src_as, src_base);
485
    src_area = find_area_and_lock(src_as, src_base);
488
    if (!src_area) {
486
    if (!src_area) {
489
        /*
487
        /*
490
         * Could not find the source address space area.
488
         * Could not find the source address space area.
491
         */
489
         */
492
        spinlock_unlock(&src_task->lock);
-
 
493
        mutex_unlock(&src_as->lock);
490
        mutex_unlock(&src_as->lock);
494
        interrupts_restore(ipl);
491
        interrupts_restore(ipl);
495
        return ENOENT;
492
        return ENOENT;
496
    }
493
    }
-
 
494
   
-
 
495
    if (!src_area->backend || src_area->backend != &anon_backend) {
-
 
496
        /*
-
 
497
         * As of now, only anonymous address space areas can be shared.
-
 
498
         */
-
 
499
        mutex_unlock(&src_area->lock);
-
 
500
        mutex_unlock(&src_as->lock);
-
 
501
        interrupts_restore(ipl);
-
 
502
        return ENOTSUP;
-
 
503
    }
-
 
504
   
497
    src_size = src_area->pages * PAGE_SIZE;
505
    src_size = src_area->pages * PAGE_SIZE;
498
    src_flags = src_area->flags;
506
    src_flags = src_area->flags;
499
    mutex_unlock(&src_area->lock);
-
 
500
    mutex_unlock(&src_as->lock);
-
 
501
 
507
   
502
    if (src_size != acc_size) {
508
    if (src_size != acc_size) {
-
 
509
        mutex_unlock(&src_area->lock);
503
        spinlock_unlock(&src_task->lock);
510
        mutex_unlock(&src_as->lock);
504
        interrupts_restore(ipl);
511
        interrupts_restore(ipl);
505
        return EPERM;
512
        return EPERM;
506
    }
513
    }
-
 
514
 
-
 
515
    /*
-
 
516
     * Now we are committed to sharing the area.
-
 
517
     * First prepare the area for sharing.
-
 
518
     * Then it will be safe to unlock it.
-
 
519
     */
-
 
520
    sh_info = src_area->sh_info;
-
 
521
    if (!sh_info) {
-
 
522
        sh_info = (share_info_t *) malloc(sizeof(share_info_t), 0);
-
 
523
        mutex_initialize(&sh_info->lock);
-
 
524
        sh_info->refcount = 2;
-
 
525
        btree_create(&sh_info->pagemap);
-
 
526
        src_area->sh_info = sh_info;
-
 
527
    } else {
-
 
528
        mutex_lock(&sh_info->lock);
-
 
529
        sh_info->refcount++;
-
 
530
        mutex_unlock(&sh_info->lock);
-
 
531
    }
-
 
532
 
-
 
533
    /*
-
 
534
     * Copy used portions of the area to sh_info's page map.
-
 
535
     */
-
 
536
    mutex_lock(&sh_info->lock);
-
 
537
    for (cur = src_area->used_space.leaf_head.next; cur != &src_area->used_space.leaf_head; cur = cur->next) {
-
 
538
        btree_node_t *node;
-
 
539
        int i;
-
 
540
       
-
 
541
        node = list_get_instance(cur, btree_node_t, leaf_link);
-
 
542
        for (i = 0; i < node->keys; i++) {
-
 
543
            __address base = node->key[i];
-
 
544
            count_t count = (count_t) node->value[i];
-
 
545
            int j;
-
 
546
           
-
 
547
            for (j = 0; j < count; j++) {
-
 
548
                pte_t *pte;
-
 
549
           
-
 
550
                page_table_lock(src_as, false);
-
 
551
                pte = page_mapping_find(src_as, base + j*PAGE_SIZE);
-
 
552
                ASSERT(pte && PTE_VALID(pte) && PTE_PRESENT(pte));
-
 
553
                btree_insert(&sh_info->pagemap, (base + j*PAGE_SIZE) - src_area->base,
-
 
554
                    (void *) PTE_GET_FRAME(pte), NULL);
-
 
555
                page_table_unlock(src_as, false);
-
 
556
            }
-
 
557
               
-
 
558
        }
-
 
559
    }
-
 
560
    mutex_unlock(&sh_info->lock);
-
 
561
 
-
 
562
    mutex_unlock(&src_area->lock);
-
 
563
    mutex_unlock(&src_as->lock);
-
 
564
 
507
    /*
565
    /*
508
     * Create copy of the source address space area.
566
     * Create copy of the source address space area.
509
     * The destination area is created with AS_AREA_ATTR_PARTIAL
567
     * The destination area is created with AS_AREA_ATTR_PARTIAL
510
     * attribute set which prevents race condition with
568
     * attribute set which prevents race condition with
511
     * preliminary as_page_fault() calls.
569
     * preliminary as_page_fault() calls.
Line 513... Line 571...
513
    dst_area = as_area_create(AS, src_flags, src_size, dst_base, AS_AREA_ATTR_PARTIAL, &anon_backend, NULL);
571
    dst_area = as_area_create(AS, src_flags, src_size, dst_base, AS_AREA_ATTR_PARTIAL, &anon_backend, NULL);
514
    if (!dst_area) {
572
    if (!dst_area) {
515
        /*
573
        /*
516
         * Destination address space area could not be created.
574
         * Destination address space area could not be created.
517
         */
575
         */
518
        spinlock_unlock(&src_task->lock);
576
        sh_info_remove_reference(sh_info);
-
 
577
       
519
        interrupts_restore(ipl);
578
        interrupts_restore(ipl);
520
        return ENOMEM;
579
        return ENOMEM;
521
    }
580
    }
522
   
581
   
523
    spinlock_unlock(&src_task->lock);
-
 
524
   
-
 
525
    /*
-
 
526
     * Avoid deadlock by first locking the address space with lower address.
-
 
527
     */
-
 
528
    if (AS < src_as) {
-
 
529
        mutex_lock(&AS->lock);
-
 
530
        mutex_lock(&src_as->lock);
-
 
531
    } else {
-
 
532
        mutex_lock(&AS->lock);
-
 
533
        mutex_lock(&src_as->lock);
-
 
534
    }
-
 
535
   
-
 
536
    for (i = 0; i < SIZE2FRAMES(src_size); i++) {
-
 
537
        pte_t *pte;
-
 
538
        __address frame;
-
 
539
           
-
 
540
        page_table_lock(src_as, false);
-
 
541
        pte = page_mapping_find(src_as, src_base + i*PAGE_SIZE);
-
 
542
        if (pte && PTE_VALID(pte)) {
-
 
543
            ASSERT(PTE_PRESENT(pte));
-
 
544
            frame = PTE_GET_FRAME(pte);
-
 
545
            if (!(src_flags & AS_AREA_DEVICE))
-
 
546
                frame_reference_add(ADDR2PFN(frame));
-
 
547
            page_table_unlock(src_as, false);
-
 
548
        } else {
-
 
549
            page_table_unlock(src_as, false);
-
 
550
            continue;
-
 
551
        }
-
 
552
       
-
 
553
        page_table_lock(AS, false);
-
 
554
        page_mapping_insert(AS, dst_base + i*PAGE_SIZE, frame, area_flags_to_page_flags(src_flags));
-
 
555
        page_table_unlock(AS, false);
-
 
556
    }
-
 
557
 
-
 
558
    /*
582
    /*
559
     * Now the destination address space area has been
583
     * Now the destination address space area has been
560
     * fully initialized. Clear the AS_AREA_ATTR_PARTIAL
584
     * fully initialized. Clear the AS_AREA_ATTR_PARTIAL
561
     * attribute.
585
     * attribute and set the sh_info.
562
     */
586
     */
563
    mutex_lock(&dst_area->lock);
587
    mutex_lock(&dst_area->lock);
564
    dst_area->attributes &= ~AS_AREA_ATTR_PARTIAL;
588
    dst_area->attributes &= ~AS_AREA_ATTR_PARTIAL;
-
 
589
    dst_area->sh_info = sh_info;
565
    mutex_unlock(&dst_area->lock);
590
    mutex_unlock(&dst_area->lock);
566
   
591
   
567
    mutex_unlock(&AS->lock);
-
 
568
    mutex_unlock(&src_as->lock);
-
 
569
    interrupts_restore(ipl);
592
    interrupts_restore(ipl);
570
   
593
   
571
    return 0;
594
    return 0;
572
}
595
}
573
 
596
 
Line 1476... Line 1499...
1476
         * in the pagemap of the address space area share info structure.
1499
         * in the pagemap of the address space area share info structure.
1477
         * In the case that the pagemap does not contain the respective
1500
         * In the case that the pagemap does not contain the respective
1478
         * mapping, a new frame is allocated and the mapping is created.
1501
         * mapping, a new frame is allocated and the mapping is created.
1479
         */
1502
         */
1480
        mutex_lock(&area->sh_info->lock);
1503
        mutex_lock(&area->sh_info->lock);
1481
        frame = (__address) btree_search(&area->sh_info->pagemap, ALIGN_DOWN(addr, PAGE_SIZE), &leaf);
1504
        frame = (__address) btree_search(&area->sh_info->pagemap,
-
 
1505
            ALIGN_DOWN(addr, PAGE_SIZE) - area->base, &leaf);
1482
        if (!frame) {
1506
        if (!frame) {
1483
            bool allocate = true;
1507
            bool allocate = true;
1484
            int i;
1508
            int i;
1485
           
1509
           
1486
            /*
1510
            /*
Line 1498... Line 1522...
1498
                memsetb(PA2KA(frame), FRAME_SIZE, 0);
1522
                memsetb(PA2KA(frame), FRAME_SIZE, 0);
1499
               
1523
               
1500
                /*
1524
                /*
1501
                 * Insert the address of the newly allocated frame to the pagemap.
1525
                 * Insert the address of the newly allocated frame to the pagemap.
1502
                 */
1526
                 */
1503
                btree_insert(&area->sh_info->pagemap, ALIGN_DOWN(addr, PAGE_SIZE), (void *) frame, leaf);
1527
                btree_insert(&area->sh_info->pagemap, ALIGN_DOWN(addr, PAGE_SIZE) - area->base, (void *) frame, leaf);
1504
            }
1528
            }
1505
        }
1529
        }
1506
        mutex_unlock(&area->sh_info->lock);
1530
        mutex_unlock(&area->sh_info->lock);
1507
    } else {
1531
    } else {
1508
 
1532