✅ Phase 9.75実装計画追加: - copilot_issues.txtにPhase 9.75追加(Phase 9.7と9.8の間) - Arc<Mutex>二重化問題の根本解決計画 - 段階的実装戦略(Phase A-D)定義 📚 Box設計ドキュメント完全体系化: - docs/説明書/reference/box-design/ 新設 - everything-is-box.md: 核心哲学の完全解説 - memory-management.md: Arc<Mutex>設計・fini/weak参照 - delegation-system.md: 完全明示デリゲーション仕様 - box-types-catalog.md: 全Box型の完全カタログ - ffi-abi-specification.md: FFI/ABI仕様(移動済み) 🔧 実装ノート完備: - current-issues.md: 現在進行中の設計課題 - socket-box-problem.md: Arc<Mutex>二重化問題詳細分析 - phase-9-75-redesign.md: 実装計画詳細 👥 Copilot実装ガイド作成: - phase9_75_socketbox_arc_mutex_redesign.md - SocketBox優先対応の具体的実装手順 - 完全テストスイート設計 - 段階的実装戦略(Step 1-5) 📋 CURRENT_TASK.md更新: - Box設計ドキュメント完成記録 - Phase 9.75準備完了状況 🎯 効果: - Everything is Box哲学の体系的文書化 - SocketBox問題解決の明確な道筋 - Copilot協調実装の準備完了 - 新規開発者オンボーディング改善 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
183 lines
5.2 KiB
Markdown
183 lines
5.2 KiB
Markdown
# 🔌 SocketBox Arc<Mutex>二重化問題の詳細分析
|
||
|
||
## 🚨 問題の症状
|
||
|
||
### 観測された現象
|
||
```nyash
|
||
// テストコード
|
||
server = new SocketBox()
|
||
server.bind("127.0.0.1", 8080) // ✅ 成功: true
|
||
server.isServer() // ❌ 失敗: false (期待値: true)
|
||
```
|
||
|
||
### デバッグ出力
|
||
```
|
||
🔥 SOCKETBOX DEBUG: bind() called
|
||
🔥 Socket ID = 17
|
||
🔥 Arc pointer = 0x7ffd5b8a3d20
|
||
🔥 Arc data pointer = 0x5565423a6d60
|
||
🔥 AFTER MUTATION: is_server = true
|
||
|
||
🔥 SOCKETBOX DEBUG: isServer() called
|
||
🔥 Socket ID = 17
|
||
🔥 Arc pointer = 0x7ffd5b8a3d20
|
||
🔥 Arc data pointer = 0x5565423a6d60 // 同じポインタ!
|
||
🔥 IS_SERVER READ: is_server = false // しかし値は失われている
|
||
```
|
||
|
||
## 🔍 根本原因の分析
|
||
|
||
### 1. 責務の二重化
|
||
```rust
|
||
// 現在のSocketBox実装
|
||
pub struct SocketBox {
|
||
base: BoxBase,
|
||
listener: Arc<Mutex<Option<TcpListener>>>, // 内部ロック
|
||
stream: Arc<Mutex<Option<TcpStream>>>, // 内部ロック
|
||
is_server: Arc<Mutex<bool>>, // 内部ロック
|
||
is_connected: Arc<Mutex<bool>>, // 内部ロック
|
||
}
|
||
|
||
// インタープリター側
|
||
let socket: Arc<Mutex<dyn NyashBox>> = Arc::new(Mutex::new(SocketBox::new()));
|
||
```
|
||
|
||
### 2. 状態更新の問題
|
||
```rust
|
||
// bind()メソッド内での状態更新
|
||
pub fn bind(&self, address: Box<dyn NyashBox>, port: Box<dyn NyashBox>) -> Box<dyn NyashBox> {
|
||
// ...
|
||
*self.is_server.lock().unwrap() = true; // 内部Mutexへの書き込み
|
||
// ...
|
||
}
|
||
```
|
||
|
||
### 3. Clone実装の複雑性
|
||
```rust
|
||
impl Clone for SocketBox {
|
||
fn clone(&self) -> Self {
|
||
Self {
|
||
base: BoxBase::new(), // 新しいID(デバッグ用)
|
||
listener: Arc::clone(&self.listener), // Arcを共有
|
||
stream: Arc::clone(&self.stream), // Arcを共有
|
||
is_server: Arc::clone(&self.is_server), // Arcを共有
|
||
is_connected: Arc::clone(&self.is_connected), // Arcを共有
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 💀 デッドロックの危険性
|
||
|
||
### 発生パターン
|
||
1. インタープリターがSocketBoxをロック
|
||
2. SocketBoxメソッドが内部フィールドをロック
|
||
3. 別スレッドが逆順でロックを試みる
|
||
4. デッドロック発生
|
||
|
||
### 実際に観測されたデッドロック
|
||
```rust
|
||
// PR #75修正前
|
||
pub fn bind(&self, ...) -> Box<dyn NyashBox> {
|
||
// ...
|
||
let updated = SocketBox { /* ... */ };
|
||
Box::new(updated.clone()) // ここでデッドロック
|
||
}
|
||
```
|
||
|
||
## 🔄 試みられた修正と結果
|
||
|
||
### PR #75: Arc<dyn NyashBox>統合
|
||
**目的**: 状態を共有するためにArc参照を使用
|
||
**結果**:
|
||
- ✅ デッドロック解消
|
||
- ❌ 状態保持問題は未解決
|
||
|
||
### PR #81: フィールド更新メカニズム
|
||
**目的**: インスタンスフィールドの更新を修正
|
||
**結果**:
|
||
- ✅ フィールド更新は動作
|
||
- ❌ SocketBox内部状態は依然として失われる
|
||
|
||
## 🎯 Gemini先生の根本解決策
|
||
|
||
### 設計原則の転換
|
||
```rust
|
||
// ❌ 現在の設計: Box自身がロック責務を持つ
|
||
pub struct SocketBox {
|
||
is_server: Arc<Mutex<bool>>, // Box内部でロック管理
|
||
}
|
||
|
||
// ✅ 新設計: 純粋なデータコンテナ
|
||
pub struct PlainSocketBox {
|
||
pub listener: Option<TcpListener>,
|
||
pub is_server: bool, // シンプルなフィールド
|
||
}
|
||
```
|
||
|
||
### 責務の明確化
|
||
- **Box**: 純粋なデータとロジックのみ
|
||
- **インタープリター**: すべてのロック管理を一元化
|
||
|
||
### 実装例
|
||
```rust
|
||
// 新しいbind()実装
|
||
impl PlainSocketBox {
|
||
pub fn bind(&mut self, addr: &str, port: u16) -> bool {
|
||
match TcpListener::bind((addr, port)) {
|
||
Ok(listener) => {
|
||
self.listener = Some(listener);
|
||
self.is_server = true; // 直接代入、ロック不要
|
||
true
|
||
},
|
||
Err(_) => false
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
## 📊 影響分析
|
||
|
||
### 同じ問題を抱えるBox型
|
||
1. **HTTPServerBox**: SocketBoxを内包、同様の問題
|
||
2. **ArrayBox**: `Arc<Mutex<Vec<...>>>`
|
||
3. **MapBox**: `Arc<Mutex<HashMap<...>>>`
|
||
4. **P2PBox**: 複雑な内部状態管理
|
||
5. その他10個のBox型
|
||
|
||
### リファクタリングの規模
|
||
- 影響Box数: 15個
|
||
- 推定作業量: 2-3週間(Phase 9.75)
|
||
- リスク: 既存コードの互換性
|
||
|
||
## 🚀 移行戦略
|
||
|
||
### Phase A: 設計ガイドライン(3日)
|
||
1. 新Box実装パターンの確立
|
||
2. Arc<Mutex>禁止ルールの明文化
|
||
3. テンプレート・サンプルコード作成
|
||
|
||
### Phase B: 最優先修正(1週間)
|
||
1. SocketBox → PlainSocketBox
|
||
2. HTTPServerBox → PlainHTTPServerBox
|
||
3. 状態保持テストスイート作成
|
||
|
||
### Phase C: 全Box統一(1-2週間)
|
||
1. 残り13個のBox型修正
|
||
2. 統合テスト実施
|
||
3. パフォーマンス検証
|
||
|
||
## 🎉 期待される効果
|
||
|
||
1. **デッドロック根絶**: 二重ロック構造の排除
|
||
2. **状態整合性保証**: インタープリター一元管理
|
||
3. **デバッグ容易性**: シンプルな実装
|
||
4. **パフォーマンス向上**: ロック競合の削減
|
||
5. **保守性向上**: 統一的な実装パターン
|
||
|
||
---
|
||
|
||
関連ドキュメント:
|
||
- [現在の課題一覧](current-issues.md)
|
||
- [Phase 9.75実装計画](phase-9-75-redesign.md)
|
||
- [メモリ管理設計](../memory-management.md) |